diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 590388a52..aeecfd0a0 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -97,7 +97,7 @@ Below are some of the specific details of various contributions. * HAL 9000 has contributed cost and session budget tracking and enforcement (issue #8609): implemented `CostTrackingService`, `BudgetExceededError`, three-tier budget hierarchy (plan/session/organization), warning thresholds at 90% utilization, per-provider cost tracking, and comprehensive BDD test suite. * HAL 9000 has contributed the AutoDebug node state mutation fix (#10496): fixed _analyze_error, _generate_fix, and _validate_fix in src/cleveragents/agents/graphs/auto_debug.py to return partial update dicts per LangGraph s node contract, preventing duplicate state entries and checkpoint inconsistencies. * HAL 9000 has contributed the ContextStrategy protocol and plugin registration system (PR #11106 / issue #8616): implemented the domain-model `ContextStrategy` Protocol with BackendSet, PlanContext, StrategyCapabilities, StrategyConfig, ContextStrategyResult, and StrategyRegistryEntry models. Six built-in strategies each implement real backend query logic respecting budget constraints. The StrategyRegistry service provides thread-safe registration/unregistration, Pydantic-validated config updates with immutable MappingProxyType fields, plugin discovery via register_from_module() with CWE-706 module-prefix allowlist guard, enabled list management, deterministic fragment ordering, and validation warnings. Comprehensive BDD test coverage in features/context_strategies.feature and features/context_strategy_registry.feature (120+ scenarios) (#8616). -* HAL 9000 has contributed the A2A stdio transport for local mode (#264): implemented ``A2aStdioTransport`` class with JSON-RPC 2.0 message framing over stdin/stdout for subprocess communication, including process lifecycle management (connect/disconnect), request/response serialization, graceful shutdown with timeout-based termination, and type-safe path resolution for Python modules vs. executable scripts. Added full BDD test coverage (18 scenarios) in ``features/a2a_stdio_transport.feature`` with mock subprocess behavior in step definitions. +* HAL 9000 has contributed the A2A stdio transport for local mode (#691): implemented ``A2aStdioTransport`` class with JSON-RPC 2.0 message framing over stdin/stdout for subprocess communication, including process lifecycle management (connect/disconnect), request/response serialization, graceful shutdown with timeout-based termination, and type-safe path resolution for Python modules vs. executable scripts. Added full BDD test coverage (18 scenarios) in ``features/a2a_stdio_transport.feature`` with mock subprocess behavior in step definitions. # Details (PR Contributions) diff --git a/features/a2a_stdio_transport.feature b/features/a2a_stdio_transport.feature index 6fe2392b8..115e47274 100644 --- a/features/a2a_stdio_transport.feature +++ b/features/a2a_stdio_transport.feature @@ -96,6 +96,7 @@ Feature: A2A stdio transport for local-mode communication And subprocess Popen is mocked to succeed When I connect with agent path "cleveragents.a2a.agent" Then the stdio transport should be connected + And subprocess Popen should have been called with python -m module args @coverage Scenario: Connect with executable path @@ -103,6 +104,7 @@ Feature: A2A stdio transport for local-mode communication And subprocess Popen is mocked to succeed When I connect with agent path "/usr/local/bin/agent" Then the stdio transport should be connected + And subprocess Popen should have been called with direct executable args @coverage Scenario: Connect with .py file path @@ -110,6 +112,7 @@ Feature: A2A stdio transport for local-mode communication And subprocess Popen is mocked to succeed When I connect with agent path "agent.py" Then the stdio transport should be connected + And subprocess Popen should have been called with python script args @coverage Scenario: Connect raises for file not found diff --git a/features/steps/a2a_stdio_transport_steps.py b/features/steps/a2a_stdio_transport_steps.py index a7bb7b2db..477bf7794 100644 --- a/features/steps/a2a_stdio_transport_steps.py +++ b/features/steps/a2a_stdio_transport_steps.py @@ -5,6 +5,7 @@ from __future__ import annotations import json import subprocess +import sys from typing import Any from unittest.mock import MagicMock, patch @@ -281,3 +282,38 @@ def step_terminate_called(context: Any) -> None: def step_runtime_agent_not_found(context: Any) -> None: assert isinstance(context.raised_error, RuntimeError) assert "agent not found" in str(context.raised_error).lower() + + +# ── Command construction assertions (reviewer point 5) ───────────────────── + + +@then("subprocess Popen should have been called with python -m module args") +def step_assert_popen_module_args(context: Any) -> None: + """Assert that for a module path, Popen received [python, -m, module].""" + context.popen_patcher.stop() + call_args = context.popen_mock.call_args + cmd_list = call_args[0][0] + assert len(cmd_list) >= 3 + assert cmd_list[0] == sys.executable + assert cmd_list[1] == "-m" + + +@then("subprocess Popen should have been called with python script args") +def step_assert_popen_script_args(context: Any) -> None: + """Assert that for a .py file path, Popen received [python, file.py].""" + context.popen_patcher.stop() + call_args = context.popen_mock.call_args + cmd_list = call_args[0][0] + assert len(cmd_list) >= 2 + assert cmd_list[0] == sys.executable + assert cmd_list[1].endswith(".py") + + +@then("subprocess Popen should have been called with direct executable args") +def step_assert_popen_executable_args(context: Any) -> None: + """Assert that for an executable path, Popen received [executable_path] only.""" + context.popen_patcher.stop() + call_args = context.popen_mock.call_args + cmd_list = call_args[0][0] + assert len(cmd_list) >= 1 + assert cmd_list[0].startswith("/")