diff --git a/components/runners/ambient-runner/ambient_runner/bridges/gemini_cli/session.py b/components/runners/ambient-runner/ambient_runner/bridges/gemini_cli/session.py index c8ee67534..2b420ec3a 100644 --- a/components/runners/ambient-runner/ambient_runner/bridges/gemini_cli/session.py +++ b/components/runners/ambient-runner/ambient_runner/bridges/gemini_cli/session.py @@ -152,6 +152,7 @@ async def query( stderr=asyncio.subprocess.PIPE, cwd=self._cwd, env=env, + limit=10 * 1024 * 1024, # 10 MB — default 64 KB is too small for large MCP tool responses ) # Start concurrent stderr streaming diff --git a/components/runners/ambient-runner/tests/test_gemini_session.py b/components/runners/ambient-runner/tests/test_gemini_session.py index 94fbaf260..5ac60edb5 100644 --- a/components/runners/ambient-runner/tests/test_gemini_session.py +++ b/components/runners/ambient-runner/tests/test_gemini_session.py @@ -78,6 +78,44 @@ async def _wait(): # ------------------------------------------------------------------ +class TestWorkerSubprocessConfig: + """Verify subprocess configuration passed to create_subprocess_exec.""" + + @pytest.mark.asyncio + async def test_stream_buffer_limit_raised(self): + """The subprocess must use a 10 MB buffer limit to handle large MCP tool responses.""" + worker = GeminiSessionWorker(model="gemini-2.5-flash", api_key="key1") + proc = _make_mock_process( + stdout_lines=[b'{"type":"result"}\n'], + stderr_lines=[], + ) + + with patch("asyncio.create_subprocess_exec", return_value=proc) as mock_exec: + async for _ in worker.query("test"): + pass + + call_kwargs = mock_exec.call_args[1] + assert call_kwargs["limit"] == 10 * 1024 * 1024 + + @pytest.mark.asyncio + async def test_large_stdout_line_does_not_crash(self): + """A real subprocess outputting >64 KB on one line must not raise ValueError. + + Without the 10 MB limit the default 64 KB StreamReader would blow up with: + ValueError: Separator is found, but chunk is longer than limit + """ + payload = "x" * 100_000 # 100 KB — well above the old 64 KB default + proc = await asyncio.create_subprocess_exec( + "python3", "-c", f'print("{payload}")', + stdout=asyncio.subprocess.PIPE, + limit=10 * 1024 * 1024, + ) + line = await proc.stdout.readline() + await proc.wait() + assert len(line) > 64 * 1024 + assert proc.returncode == 0 + + class TestWorkerCommandConstruction: """Verify the CLI command built by query()."""