mirror of
https://github.com/usestrix/strix.git
synced 2026-08-23 11:22:37 +02:00
Drop our 797-LoC manual GraphQL ``ProxyManager`` and the in-container
sandbox dispatch. Caido goes host-side via the official async Python
SDK. The Caido CLI still runs as a sidecar in the container — only the
control-plane moves.
Bootstrap moves host-side:
- New ``strix/sandbox/caido_bootstrap.py``: ``loginAsGuest`` via
aiohttp (5 retries), then ``client.project.create(temporary=True)``
+ ``client.project.select(...)``, then return the connected
``caido_sdk_client.Client``. Drop the equivalent bash from
``docker-entrypoint.sh`` (~60 lines of curl + jq).
- ``entry.py`` calls ``bootstrap_caido_client`` after the
``wait_for_tcp_ready`` healthcheck, stashes the client in the bundle
and threads it through ``make_agent_context(caido_client=...)``.
``agents_graph.create_agent`` propagates the same client to children.
- ``session_manager.cleanup`` ``await``s ``client.aclose()`` before
tearing down the container.
- Drop ``CAIDO_PORT`` from the manifest env (only the in-container
ProxyManager read it) and ``CAIDO_API_TOKEN`` from the entrypoint's
``/etc/profile.d/proxy.sh`` + ``/etc/environment`` heredocs.
Tools (``strix/tools/proxy/tools.py``):
- ``list_requests`` → ``client.request.list().filter().first().after()``
with ascending/descending order. **Pagination changes from
start_page/end_page (1-indexed) to first/after cursors** matching the
SDK's native shape; response includes ``page_info.end_cursor`` for
the model to thread.
- ``view_request`` → ``client.request.get(id, RequestGetOptions(...))``;
decode raw bytes locally; existing regex-search and line-pagination
modes preserved.
- ``send_request`` → synthesize raw HTTP bytes, parse URL into
``ConnectionInfoInput(host, port, is_tls)``, create a replay session
via ``client.replay.sessions.create(CreateReplaySessionFromRaw(...))``,
then ``client.replay.send(session_id, ReplaySendOptions(...))``.
- ``repeat_request`` → ``client.request.get(id, request_raw=True)`` →
port the existing parse/_apply_modifications/build helpers verbatim →
send via the same replay flow as ``send_request``.
- ``scope_rules`` → direct mapping to ``client.scope.{list, get, create,
update, delete}``.
- **Drop ``list_sitemap`` + ``view_sitemap_entry``** — the official SDK
has no sitemap module. The model uses HTTPQL filters
(``req.host.eq:"X" AND req.path.cont:"/api/"``) for the same
drill-down workflow.
Deletions:
- ``strix/tools/proxy/proxy_manager.py`` (797 LoC)
- ``strix/tools/proxy/proxy_actions.py`` (113 LoC)
- The 6-line proxy_actions pre-import in ``python_instance.py``
(broken once proxy_actions is gone; that file is queued for deletion
in commit 2 anyway).
Deps:
- Add ``caido-sdk-client>=0.2.0`` and ``aiohttp>=3.10.0`` to runtime
``[project] dependencies``.
- Drop ``gql[requests]>=3.5.3`` from ``[project.optional-dependencies]
sandbox`` — only the in-container ProxyManager used the sync transport
variant; the SDK pulls in ``gql[aiohttp]`` transitively for us.
- ``[[tool.mypy.overrides]]``: add ``caido_sdk_client.*`` and
``aiohttp.*`` to the missing-imports list with
``disable_error_code=["import-untyped"]`` (neither ships ``py.typed``).
- ``[tool.ruff.lint.per-file-ignores]``: bump the proxy/tools.py
ignore to also include ``PLR0911`` (the scope_rules action dispatcher
has many short-circuit returns).
ruff drops from 21 → 12 errors; mypy moves from 82 → 84 (the +2 are in
already-flaky files unrelated to this change). All touched files mypy
clean.
163 lines
5.4 KiB
Python
163 lines
5.4 KiB
Python
"""``make_run_config`` — assemble a Strix-flavored ``RunConfig`` for ``Runner.run``.
|
|
|
|
Every scan goes through here so defaults apply uniformly. Per-call
|
|
overrides land via ``model_settings_override``.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, Any, Literal
|
|
|
|
from agents import RunConfig
|
|
from agents.model_settings import ModelSettings
|
|
from agents.retry import (
|
|
ModelRetryBackoffSettings,
|
|
ModelRetrySettings,
|
|
retry_policies,
|
|
)
|
|
from agents.sandbox import SandboxRunConfig
|
|
from openai.types.shared import Reasoning
|
|
|
|
from strix.llm.multi_provider_setup import build_multi_provider
|
|
from strix.orchestration.filter import inject_messages_filter
|
|
|
|
|
|
if TYPE_CHECKING:
|
|
from agents.sandbox.session.base_sandbox_session import BaseSandboxSession
|
|
|
|
from strix.orchestration.bus import AgentMessageBus
|
|
|
|
|
|
#: Default ``max_turns`` callers should pass to ``Runner.run``.
|
|
STRIX_DEFAULT_MAX_TURNS = 300
|
|
|
|
# Retry: 5 attempts with ``min(90, 2*2^n)`` backoff. 4xx auth/validation
|
|
# errors are excluded from the retryable status list — they can't be
|
|
# fixed by retrying and should fail fast.
|
|
_DEFAULT_RETRY = ModelRetrySettings(
|
|
max_retries=5,
|
|
backoff=ModelRetryBackoffSettings(
|
|
initial_delay=2.0,
|
|
max_delay=90.0,
|
|
multiplier=2.0,
|
|
jitter=False,
|
|
),
|
|
policy=retry_policies.any(
|
|
retry_policies.provider_suggested(),
|
|
retry_policies.network_error(),
|
|
retry_policies.http_status((429, 500, 502, 503, 504)),
|
|
),
|
|
)
|
|
|
|
|
|
def make_run_config(
|
|
*,
|
|
sandbox_session: BaseSandboxSession | None,
|
|
model: str = "anthropic/claude-sonnet-4-6",
|
|
reasoning_effort: Literal["low", "medium", "high"] | None = None,
|
|
model_settings_override: ModelSettings | None = None,
|
|
sandbox_client: Any | None = None,
|
|
) -> RunConfig:
|
|
"""Build a ``RunConfig`` with Strix defaults.
|
|
|
|
Note: ``max_turns`` is not a ``RunConfig`` field — pass it directly
|
|
to ``Runner.run``. ``STRIX_DEFAULT_MAX_TURNS`` is the budget Strix
|
|
uses.
|
|
|
|
Args:
|
|
sandbox_session: Live sandbox session shared by every agent in
|
|
this scan (one container per scan; see
|
|
:mod:`strix.sandbox.session_manager`). ``None`` is allowed
|
|
for unit tests and dry runs.
|
|
model: Model alias passed to ``MultiProvider``. Defaults to the
|
|
production Anthropic alias.
|
|
reasoning_effort: ``"low" | "medium" | "high"``; routes to
|
|
``ModelSettings.reasoning``.
|
|
model_settings_override: Optional per-run ``ModelSettings``
|
|
merged over factory defaults.
|
|
sandbox_client: Optional pre-built sandbox client (Strix Docker
|
|
subclass). The SDK instantiates its built-in if a session is
|
|
supplied without a client.
|
|
"""
|
|
base_settings = ModelSettings(
|
|
parallel_tool_calls=False,
|
|
tool_choice="required",
|
|
retry=_DEFAULT_RETRY,
|
|
)
|
|
if reasoning_effort is not None:
|
|
base_settings = base_settings.resolve(
|
|
ModelSettings(reasoning=Reasoning(effort=reasoning_effort)),
|
|
)
|
|
if model_settings_override is not None:
|
|
base_settings = base_settings.resolve(model_settings_override)
|
|
|
|
sandbox_config = (
|
|
SandboxRunConfig(client=sandbox_client, session=sandbox_session)
|
|
if sandbox_session is not None
|
|
else None
|
|
)
|
|
|
|
return RunConfig(
|
|
model=model,
|
|
model_provider=build_multi_provider(),
|
|
model_settings=base_settings,
|
|
sandbox=sandbox_config,
|
|
call_model_input_filter=inject_messages_filter,
|
|
tracing_disabled=False,
|
|
trace_include_sensitive_data=False,
|
|
)
|
|
|
|
|
|
def make_agent_context(
|
|
*,
|
|
bus: AgentMessageBus,
|
|
sandbox_session: BaseSandboxSession | None,
|
|
sandbox_token: str | None,
|
|
tool_server_host_port: int | None,
|
|
caido_host_port: int | None,
|
|
agent_id: str,
|
|
parent_id: str | None,
|
|
tracer: Any | None,
|
|
model: str = "anthropic/claude-sonnet-4-6",
|
|
model_settings: ModelSettings | None = None,
|
|
max_turns: int = 300,
|
|
is_whitebox: bool = False,
|
|
diff_scope: dict[str, Any] | None = None,
|
|
run_id: str | None = None,
|
|
sandbox_client: Any | None = None,
|
|
agent_factory: Any | None = None,
|
|
caido_client: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
"""Build the per-agent ``context`` dict passed to ``Runner.run(context=...)``.
|
|
|
|
The canonical place where bus, sandbox handles, identity, tracer
|
|
reference, and per-agent toggles live. Tools, hooks, and
|
|
``inject_messages_filter`` reach in via ``ctx.context.get(...)``.
|
|
|
|
``agent_factory`` is a callable ``(name, skills) -> agents.Agent`` —
|
|
the ``create_agent`` graph tool uses it to spin up children that
|
|
inherit the same wiring. ``sandbox_client`` is the host-side Docker
|
|
subclass, reused across child runs.
|
|
"""
|
|
return {
|
|
"bus": bus,
|
|
"sandbox_session": sandbox_session,
|
|
"sandbox_client": sandbox_client,
|
|
"sandbox_token": sandbox_token,
|
|
"tool_server_host_port": tool_server_host_port,
|
|
"caido_host_port": caido_host_port,
|
|
"caido_client": caido_client,
|
|
"agent_id": agent_id,
|
|
"parent_id": parent_id,
|
|
"tracer": tracer,
|
|
"model": model,
|
|
"model_settings": model_settings,
|
|
"max_turns": max_turns,
|
|
"turn_count": 0,
|
|
"agent_finish_called": False,
|
|
"is_whitebox": is_whitebox,
|
|
"diff_scope": diff_scope,
|
|
"run_id": run_id,
|
|
"agent_factory": agent_factory,
|
|
}
|