From 04ad13c9e473d9acb2db5152a06a5c889a0b581f Mon Sep 17 00:00:00 2001 From: vominh1919 Date: Sun, 10 May 2026 20:41:59 +0700 Subject: [PATCH] fix: replace mutable default arguments with None in StatefulToolEnv and MCPEnv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two instances of the classic Python mutable default argument bug: 1. StatefulToolEnv.add_tool(args_to_skip=[]) — the default [] is created once at function definition time and shared across all calls. If any caller mutates it (e.g., args_to_skip.append(...)), subsequent calls without an explicit argument see the mutated list. 2. MCPEnv.__init__(mcp_servers=[]) — same issue. The default list is shared across all MCPEnv instances that don't pass mcp_servers explicitly. Fix: Replace `=[]` with `=None` and initialize inside the function body. --- verifiers/envs/experimental/mcp_env.py | 4 ++-- verifiers/envs/stateful_tool_env.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/verifiers/envs/experimental/mcp_env.py b/verifiers/envs/experimental/mcp_env.py index 542b0866f..18b09222b 100644 --- a/verifiers/envs/experimental/mcp_env.py +++ b/verifiers/envs/experimental/mcp_env.py @@ -148,13 +148,13 @@ def __init__( self, # MCPEnv is designed for global server processes, not per-rollout, # stateful server instances with mutable task-specific data. - mcp_servers: List[MCPServerConfig | dict] = [], + mcp_servers: List[MCPServerConfig | dict] | None = None, max_turns: int = 10, error_formatter: Callable[[Exception], str] = lambda e: f"Error: {str(e)}", **kwargs, ): self.mcp_servers: List[MCPServerConfig] = [] - if mcp_servers: + if mcp_servers is not None: for server in mcp_servers: if isinstance(server, MCPServerConfig): self.mcp_servers.append(server) diff --git a/verifiers/envs/stateful_tool_env.py b/verifiers/envs/stateful_tool_env.py index cb44555a4..37cdc1b52 100644 --- a/verifiers/envs/stateful_tool_env.py +++ b/verifiers/envs/stateful_tool_env.py @@ -66,7 +66,7 @@ def __init__( self.skipped_args: dict[str, list[str]] = {} self.max_turns: int = max_turns - def add_tool(self, tool: Callable, args_to_skip: list[str] = []): + def add_tool(self, tool: Callable, args_to_skip: list[str] | None = None): """Add a tool, optionally hiding arguments from the agent's view. Skipped args are removed from the schema shown to the agent but can be @@ -75,6 +75,8 @@ def add_tool(self, tool: Callable, args_to_skip: list[str] = []): Assumes all non-skipped args use standard JSON types (no remaining $ref/$defs). """ + if args_to_skip is None: + args_to_skip = [] self.tools.append(tool) tool_def = convert_func_to_tool_def(filter_signature(tool, args_to_skip)) params = tool_def.parameters