diff --git a/strix/core/execution.py b/strix/core/execution.py index 06dc3ddf5..f252e3008 100644 --- a/strix/core/execution.py +++ b/strix/core/execution.py @@ -349,6 +349,15 @@ async def _run_cycle( # noqa: PLR0912, PLR0915 while True: try: await coordinator.mark_running(agent_id) + + # --- PRODUCTION FIX FOR AWS BEDROCK TOOL_CHOICE COMPLIANCE --- + if hasattr(run_config, "extra_body") and isinstance(run_config.extra_body, dict): + if "tool_choice" in run_config.extra_body: + run_config.extra_body["tool_choice"] = {"type": "auto"} + elif hasattr(run_config, "tool_choice") and (run_config.tool_choice == "auto" or isinstance(run_config.tool_choice, str)): + run_config.tool_choice = {"type": "auto"} + # ------------------------------------------------------------- + stream = Runner.run_streamed( agent, input=input_data, diff --git a/strix/runtime/backends.py b/strix/runtime/backends.py index d7eba3357..7d8a464ea 100644 --- a/strix/runtime/backends.py +++ b/strix/runtime/backends.py @@ -3,6 +3,8 @@ from __future__ import annotations import logging +import os +import sys from collections.abc import Awaitable, Callable from typing import TYPE_CHECKING, Any @@ -47,11 +49,46 @@ async def _docker_backend( from strix.runtime.docker_client import StrixDockerSandboxClient + # Handle Issue #671 Edge Cases + concurrency_limits = None + default_limit = 1 if sys.platform == "win32" else None + limit_val = os.environ.get("STRIX_DOCKER_CONCURRENCY", default_limit) + + if limit_val is not None: + try: + # Prevents <= 0 limits breaking the SDK validation + limit = max(1, int(limit_val)) + + # Try primary import path, fallback if SDK changes + try: + from agents.sandbox.artifacts import SandboxConcurrencyLimits + except ImportError: + from agents.sandbox import SandboxConcurrencyLimits + + concurrency_limits = SandboxConcurrencyLimits( + manifest_entries=limit, + local_dir_files=limit + ) + logger.debug(f"Applied SandboxConcurrencyLimits: {limit}") + except (ImportError, ValueError) as e: + if sys.platform == "win32" and limit_val == 1: + # Fail loudly on Windows to avoid silent race condition + raise RuntimeError("Failed to import SandboxConcurrencyLimits required for Windows execution.") from e + logger.warning("Invalid STRIX_DOCKER_CONCURRENCY or import failed. Proceeding with defaults.") + client = StrixDockerSandboxClient(docker.from_env()) client.strix_bind_mounts = bind_mounts or [] options = DockerSandboxClientOptions(image=image, exposed_ports=exposed_ports) + + # Create the session (without concurrency_limits keyword) session = await client.create(options=options, manifest=manifest) - await session.start() + + # Pass concurrency_limits where the session is actually started/materialized + start_kwargs = {} + if concurrency_limits is not None: + start_kwargs["concurrency_limits"] = concurrency_limits + + await session.start(**start_kwargs) return client, session @@ -90,4 +127,4 @@ def register_backend(name: str, backend: SandboxBackend) -> None: def supported_backends() -> list[str]: - return sorted(_BACKENDS) + return sorted(_BACKENDS) \ No newline at end of file