diff --git a/containers/proxy.py b/containers/browser-server.py similarity index 92% rename from containers/proxy.py rename to containers/browser-server.py index 2f83fe19..d055156e 100644 --- a/containers/proxy.py +++ b/containers/browser-server.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import asyncio +import logging import os import re from typing import Any @@ -8,6 +9,8 @@ import aiohttp from aiohttp import WSMsgType, web +logger = logging.getLogger(__name__) + TOKEN = os.environ["TOOL_SERVER_TOKEN"] LISTEN_PORT = int(os.environ.get("CDP_PORT", "9222")) UPSTREAM = f"http://127.0.0.1:{os.environ.get('CDP_INTERNAL_PORT', '19222')}" @@ -39,7 +42,7 @@ async def _proxy_ws(req: web.Request, url: str, headers: dict[str, Any]) -> web. elif msg.type == WSMsgType.BINARY: await dst.send_bytes(msg.data) else: - print(str.format("Unexpected WebSocket message type: %s", msg.type)) + logger.warning("Unexpected WebSocket message type: %s", msg.type) break await asyncio.gather( @@ -81,5 +84,5 @@ app = web.Application() app.router.add_route("*", "/{path:.*}", _handle) if __name__ == "__main__": - print(f"CDP auth proxy: 0.0.0.0:{LISTEN_PORT} -> {UPSTREAM}", flush=True) + logger.info("CDP auth proxy: 0.0.0.0:%s -> %s", LISTEN_PORT, UPSTREAM) web.run_app(app, host="0.0.0.0", port=LISTEN_PORT, print=None) diff --git a/pyproject.toml b/pyproject.toml index fba826a2..cb47baf0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -117,38 +117,39 @@ pretty = true # Allow some flexibility for third-party libraries [[tool.mypy.overrides]] module = [ - "litellm.*", - "tenacity.*", - "numpydoc.*", - "rich.*", - "IPython.*", - "openhands_aci.*", - "playwright.*", - "uvicorn.*", - "jinja2.*", - "pydantic_settings.*", - "jwt.*", - "httpx.*", - "gql.*", - "textual.*", - "pyte.*", - "libtmux.*", - "pytest.*", - "cvss.*", - "opentelemetry.*", - "scrubadub.*", - "traceloop.*", - "browser_use", - "browser_use.*", - "cdp_use", - "cdp_use.*", - "aiohttp", - "aiohttp.*", + "litellm.*", + "tenacity.*", + "numpydoc.*", + "rich.*", + "IPython.*", + "openhands_aci.*", + "playwright.*", + "uvicorn.*", + "jinja2.*", + "pydantic_settings.*", + "jwt.*", + "httpx.*", + "gql.*", + "textual.*", + "pyte.*", + "libtmux.*", + "pytest.*", + "cvss.*", + "opentelemetry.*", + "scrubadub.*", + "traceloop.*", + "browser_use", + "browser_use.*", + "cdp_use", + "cdp_use.*", + "aiohttp", + "aiohttp.*", ] ignore_missing_imports = true +# We need to override this for extending LLM base models [[tool.mypy.overrides]] -module = ["strix.tools.browser.*"] +module = ["strix.tools.browser.litellm.*"] disallow_subclassing_any = false # Relax strict rules for test files (pytest decorators are not fully typed) @@ -165,94 +166,90 @@ disallow_untyped_defs = false target-version = "py312" line-length = 100 extend-exclude = [ - ".git", - ".mypy_cache", - ".pytest_cache", - ".ruff_cache", - "__pycache__", - "build", - "dist", - "migrations", + ".git", + ".mypy_cache", + ".pytest_cache", + ".ruff_cache", + "__pycache__", + "build", + "dist", + "migrations", ] [tool.ruff.lint] # Enable comprehensive rule sets select = [ - "E", # pycodestyle errors - "W", # pycodestyle warnings - "F", # Pyflakes - "I", # isort - "N", # pep8-naming - "UP", # pyupgrade - "YTT", # flake8-2020 - "S", # flake8-bandit - "BLE", # flake8-blind-except - "FBT", # flake8-boolean-trap - "B", # flake8-bugbear - "A", # flake8-builtins - "COM", # flake8-commas - "C4", # flake8-comprehensions - "DTZ", # flake8-datetimez - "T10", # flake8-debugger - "EM", # flake8-errmsg - "FA", # flake8-future-annotations - "ISC", # flake8-implicit-str-concat - "ICN", # flake8-import-conventions - "G", # flake8-logging-format - "INP", # flake8-no-pep420 - "PIE", # flake8-pie - "T20", # flake8-print - "PYI", # flake8-pyi - "PT", # flake8-pytest-style - "Q", # flake8-quotes - "RSE", # flake8-raise - "RET", # flake8-return - "SLF", # flake8-self - "SIM", # flake8-simplify - "TID", # flake8-tidy-imports - "TCH", # flake8-type-checking - "ARG", # flake8-unused-arguments - "PTH", # flake8-use-pathlib - "ERA", # eradicate - "PD", # pandas-vet - "PGH", # pygrep-hooks - "PL", # Pylint - "TRY", # tryceratops - "FLY", # flynt - "PERF", # Perflint - "RUF", # Ruff-specific rules + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # Pyflakes + "I", # isort + "N", # pep8-naming + "UP", # pyupgrade + "YTT", # flake8-2020 + "S", # flake8-bandit + "BLE", # flake8-blind-except + "FBT", # flake8-boolean-trap + "B", # flake8-bugbear + "A", # flake8-builtins + "COM", # flake8-commas + "C4", # flake8-comprehensions + "DTZ", # flake8-datetimez + "T10", # flake8-debugger + "EM", # flake8-errmsg + "FA", # flake8-future-annotations + "ISC", # flake8-implicit-str-concat + "ICN", # flake8-import-conventions + "G", # flake8-logging-format + "INP", # flake8-no-pep420 + "PIE", # flake8-pie + "T20", # flake8-print + "PYI", # flake8-pyi + "PT", # flake8-pytest-style + "Q", # flake8-quotes + "RSE", # flake8-raise + "RET", # flake8-return + "SLF", # flake8-self + "SIM", # flake8-simplify + "TID", # flake8-tidy-imports + "TCH", # flake8-type-checking + "ARG", # flake8-unused-arguments + "PTH", # flake8-use-pathlib + "ERA", # eradicate + "PD", # pandas-vet + "PGH", # pygrep-hooks + "PL", # Pylint + "TRY", # tryceratops + "FLY", # flynt + "PERF", # Perflint + "RUF", # Ruff-specific rules ] ignore = [ - "S101", # Use of assert - "S104", # Possible binding to all interfaces - "S301", # Use of pickle - "COM812", # Missing trailing comma (handled by formatter) - "ISC001", # Single line implicit string concatenation (handled by formatter) - "PLR0913", # Too many arguments to function call - "TRY003", # Avoid specifying long messages outside the exception class - "EM101", # Exception must not use a string literal - "EM102", # Exception must not use an f-string literal - "FBT001", # Boolean positional arg in function definition - "FBT002", # Boolean default positional argument in function definition - "G004", # Logging statement uses f-string - "PLR2004", # Magic value used in comparison - "SLF001", # Private member accessed + "S101", # Use of assert + "S104", # Possible binding to all interfaces + "S301", # Use of pickle + "COM812", # Missing trailing comma (handled by formatter) + "ISC001", # Single line implicit string concatenation (handled by formatter) + "PLR0913", # Too many arguments to function call + "TRY003", # Avoid specifying long messages outside the exception class + "EM101", # Exception must not use a string literal + "EM102", # Exception must not use an f-string literal + "FBT001", # Boolean positional arg in function definition + "FBT002", # Boolean default positional argument in function definition + "G004", # Logging statement uses f-string + "PLR2004", # Magic value used in comparison + "SLF001", # Private member accessed ] [tool.ruff.lint.per-file-ignores] -"containers/**/*.py" = [ - "T201", # print is the only logging mechanism in container scripts -] "tests/**/*.py" = [ - "S106", # Possible hardcoded password - "S108", # Possible insecure usage of temporary file/directory - "ARG001", # Unused function argument - "FBT003", # Boolean positional value in function call - "PLR2004", # Magic value used in comparison + "S106", # Possible hardcoded password + "S108", # Possible insecure usage of temporary file/directory + "ARG001", # Unused function argument + "PLR2004", # Magic value used in comparison ] "strix/tools/**/*.py" = [ - "ARG001", # Unused function argument (tools may have unused args for interface consistency) + "ARG001", # Unused function argument (tools may have unused args for interface consistency) ] "strix/tools/browser/**/*.py" = [ "ARG002", # Unused method argument (interface methods may not use all args) @@ -359,12 +356,12 @@ known_third_party = ["fastapi", "pydantic", "litellm", "tenacity"] [tool.pytest.ini_options] minversion = "6.0" addopts = [ - "--strict-markers", - "--strict-config", - "--cov=strix", - "--cov-report=term-missing", - "--cov-report=html", - "--cov-report=xml", + "--strict-markers", + "--strict-config", + "--cov=strix", + "--cov-report=term-missing", + "--cov-report=html", + "--cov-report=xml", ] testpaths = ["tests"] python_files = ["test_*.py", "*_test.py"] @@ -374,20 +371,24 @@ asyncio_mode = "auto" [tool.coverage.run] source = ["strix"] -omit = ["*/tests/*", "*/migrations/*", "*/__pycache__/*"] +omit = [ + "*/tests/*", + "*/migrations/*", + "*/__pycache__/*" +] [tool.coverage.report] exclude_lines = [ - "pragma: no cover", - "def __repr__", - "if self.debug:", - "if settings.DEBUG", - "raise AssertionError", - "raise NotImplementedError", - "if 0:", - "if __name__ == .__main__.:", - "class .*\\bProtocol\\):", - "@(abc\\.)?abstractmethod", + "pragma: no cover", + "def __repr__", + "if self.debug:", + "if settings.DEBUG", + "raise AssertionError", + "raise NotImplementedError", + "if 0:", + "if __name__ == .__main__.:", + "class .*\\bProtocol\\):", + "@(abc\\.)?abstractmethod", ] # ============================================================================ @@ -396,11 +397,5 @@ exclude_lines = [ [tool.bandit] exclude_dirs = ["tests", "docs", "build", "dist"] -skips = [ - "B101", - "B601", - "B404", - "B603", - "B607", -] # Skip assert, shell injection, subprocess import and partial path checks +skips = ["B101", "B601", "B404", "B603", "B607"] # Skip assert, shell injection, subprocess import and partial path checks severity = "medium" diff --git a/strix/runtime/tool_server.py b/strix/runtime/tool_server.py index 913ce483..66ed26e4 100644 --- a/strix/runtime/tool_server.py +++ b/strix/runtime/tool_server.py @@ -18,6 +18,7 @@ if not SANDBOX_MODE: raise RuntimeError("Tool server should only run in sandbox mode (STRIX_SANDBOX_MODE=true)") parser = argparse.ArgumentParser(description="Start Strix tool server") +parser.add_argument("--token", required=True, help="Authentication token") parser.add_argument("--host", default="0.0.0.0", help="Host to bind to") # nosec parser.add_argument("--port", type=int, required=True, help="Port to bind to") parser.add_argument( @@ -28,11 +29,7 @@ parser.add_argument( ) args = parser.parse_args() - -# Read token from environment to avoid leaking it in /proc//cmdline. -EXPECTED_TOKEN = os.environ.get("TOOL_SERVER_TOKEN", "") -if not EXPECTED_TOKEN: - raise RuntimeError("TOOL_SERVER_TOKEN environment variable must be set") +EXPECTED_TOKEN = args.token REQUEST_TIMEOUT = args.timeout app = FastAPI() diff --git a/strix/telemetry/utils.py b/strix/telemetry/utils.py index 8ed8226d..826a46f9 100644 --- a/strix/telemetry/utils.py +++ b/strix/telemetry/utils.py @@ -353,7 +353,6 @@ def bootstrap_otel( "block_instruments": { Instruments.URLLIB3, Instruments.REQUESTS, - Instruments.LANGCHAIN, }, } if remote_enabled: