From 532788d4099854a2bf02552e92a388fd513b924e Mon Sep 17 00:00:00 2001 From: Adam Moussa Date: Fri, 17 Jul 2026 13:57:20 -0400 Subject: [PATCH] refactor: adopt graphs/runtime/providers shims + retarget langgraph.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of the domain-reorg adoption (build plan step C3): fork content, upstream layout. Adds agent/graphs/{agent,analyzer,chat,reviewer, scheduler}.py as thin re-export shims delegating to the existing fork graph factories (agent.server/analyzer/chat/reviewer/scheduler), plus agent/providers/__init__.py re-exporting agent.utils.model's make_model/provider_model_kwargs/fallback_model_id_for surface — verbatim upstream content, verified each import resolves against fork modules with no name changes needed. agent/runtime/{constants,execution}.py deviate from upstream's verbatim shim bodies: rather than duplicating DEFAULT_LLM_MODEL_ID/ DEFAULT_LLM_MAX_TOKENS/DEFAULT_RECURSION_LIMIT/MODEL_CALL_RECURSION_LIMIT and graph_loaded_for_execution's logic (upstream's shims assume agent/server.py already had these extracted into runtime/ modules, which is out of this commit's scope — server.py is untouched), they import the fork's existing agent.server attributes directly. This keeps the values/logic single-sourced instead of forking a second copy that could drift. agent/runtime/sandbox.py's delegation targets also differ from upstream: fork's sandbox lifecycle helpers are private (_get_cached_sandbox_backend, _configure_git_identity, _recreate_sandbox in agent/server.py) since the fork's sync 4-case `__creating__` sentinel design (AGENTS.md) never made them public. get_cached_sandbox_backend() also drops upstream's caller-supplied `reconnect` callback parameter — fork's _get_cached_sandbox_backend is a plain cache lookup; reconnection is handled internally by ensure_sandbox_for_thread/ check_or_recreate_sandbox, not via a passed-in callback. No other signature changes. Added fork-only agent/graphs/ci_monitor.py (delegates to agent.ci_monitor:get_ci_monitor) for symmetry, since upstream deleted its ci-autofix cluster and has no equivalent shim. langgraph.json's five stock graph entrypoints plus the fork-only ci_monitor now all point at agent.graphs.; http.app stays agent.webapp:app (unchanged, per plan). Deliberately NOT included (owned by build plan step C4, the FastAPI split, gated on /sh-security-review): agent/api/{__init__,app, health}.py, agent/webhooks/common.py, and the three agent/webhooks/{github,linear,slack}_routes.py files. Those aren't thin structural shims like the 21-file list implies in isolation — they carry the fork's actual webhook dispatch/verify logic split out of the still-monolithic webapp.py, which hasn't happened yet. Building them now against upstream's placeholder content would ship incomplete auth surface that C4 would just discard and redo. Pinned oven-sh/setup-bun's bun-version to 1.3.14 (the version installed locally; ui/ has no .bun-version file or package.json engines/packageManager field pinning one) across all three CI jobs that install bun, removing the latest-resolution flake. Gates: ruff check + ruff format --check (clean), pytest --co -q (1637 collected, no import errors), a direct import smoke-test of every new module's public symbols, and a make dev boot check — langgraph dev registered all six graphs (agent, reviewer, analyzer, chat, scheduler, ci_monitor) each importing from agent.graphs.*, and loaded the custom app from agent.webapp:app, before the process was killed. (The subsequent lifespan failure, "DEFAULT_SANDBOX_SNAPSHOT_ID must be set when SANDBOX_TYPE=langsmith", is expected with no .env secrets configured in this environment and unrelated to this commit.) --- .github/workflows/ci.yml | 6 +++++ agent/graphs/__init__.py | 1 + agent/graphs/agent.py | 3 +++ agent/graphs/analyzer.py | 3 +++ agent/graphs/chat.py | 3 +++ agent/graphs/ci_monitor.py | 3 +++ agent/graphs/reviewer.py | 3 +++ agent/graphs/scheduler.py | 3 +++ agent/providers/__init__.py | 15 +++++++++++ agent/runtime/__init__.py | 25 +++++++++++++++++ agent/runtime/constants.py | 13 +++++++++ agent/runtime/execution.py | 3 +++ agent/runtime/sandbox.py | 53 +++++++++++++++++++++++++++++++++++++ langgraph.json | 12 ++++----- 14 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 agent/graphs/__init__.py create mode 100644 agent/graphs/agent.py create mode 100644 agent/graphs/analyzer.py create mode 100644 agent/graphs/chat.py create mode 100644 agent/graphs/ci_monitor.py create mode 100644 agent/graphs/reviewer.py create mode 100644 agent/graphs/scheduler.py create mode 100644 agent/providers/__init__.py create mode 100644 agent/runtime/__init__.py create mode 100644 agent/runtime/constants.py create mode 100644 agent/runtime/execution.py create mode 100644 agent/runtime/sandbox.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a3a52a8..ba8ad643 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,8 @@ jobs: steps: - uses: actions/checkout@v7 - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: "1.3.14" - name: Install UI dependencies working-directory: ui run: bun install --frozen-lockfile @@ -74,6 +76,8 @@ jobs: with: node-version: "24" - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: "1.3.14" - name: Install Python deps (langgraph dev runtime) run: uv sync --locked - name: Install Playwright + Chromium @@ -132,6 +136,8 @@ jobs: steps: - uses: actions/checkout@v7 - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: "1.3.14" - name: ui/package.json and ui/bun.lock agree working-directory: ui run: bun install --frozen-lockfile diff --git a/agent/graphs/__init__.py b/agent/graphs/__init__.py new file mode 100644 index 00000000..c9c2ef67 --- /dev/null +++ b/agent/graphs/__init__.py @@ -0,0 +1 @@ +__all__: list[str] = [] diff --git a/agent/graphs/agent.py b/agent/graphs/agent.py new file mode 100644 index 00000000..943d000a --- /dev/null +++ b/agent/graphs/agent.py @@ -0,0 +1,3 @@ +from agent.server import get_agent, traced_agent + +__all__ = ["get_agent", "traced_agent"] diff --git a/agent/graphs/analyzer.py b/agent/graphs/analyzer.py new file mode 100644 index 00000000..ccc6bceb --- /dev/null +++ b/agent/graphs/analyzer.py @@ -0,0 +1,3 @@ +from agent.analyzer import get_analyzer, traced_analyzer + +__all__ = ["get_analyzer", "traced_analyzer"] diff --git a/agent/graphs/chat.py b/agent/graphs/chat.py new file mode 100644 index 00000000..985fd561 --- /dev/null +++ b/agent/graphs/chat.py @@ -0,0 +1,3 @@ +from agent.chat import get_chat_agent, traced_chat_agent + +__all__ = ["get_chat_agent", "traced_chat_agent"] diff --git a/agent/graphs/ci_monitor.py b/agent/graphs/ci_monitor.py new file mode 100644 index 00000000..6db09cce --- /dev/null +++ b/agent/graphs/ci_monitor.py @@ -0,0 +1,3 @@ +from agent.ci_monitor import get_ci_monitor + +__all__ = ["get_ci_monitor"] diff --git a/agent/graphs/reviewer.py b/agent/graphs/reviewer.py new file mode 100644 index 00000000..ff8454c2 --- /dev/null +++ b/agent/graphs/reviewer.py @@ -0,0 +1,3 @@ +from agent.reviewer import get_reviewer_agent, traced_reviewer_agent + +__all__ = ["get_reviewer_agent", "traced_reviewer_agent"] diff --git a/agent/graphs/scheduler.py b/agent/graphs/scheduler.py new file mode 100644 index 00000000..99635819 --- /dev/null +++ b/agent/graphs/scheduler.py @@ -0,0 +1,3 @@ +from agent.scheduler import get_scheduler + +__all__ = ["get_scheduler"] diff --git a/agent/providers/__init__.py b/agent/providers/__init__.py new file mode 100644 index 00000000..01b0fe26 --- /dev/null +++ b/agent/providers/__init__.py @@ -0,0 +1,15 @@ +from agent.utils.model import ( + DEFAULT_LLM_REASONING, + ModelKwargs, + fallback_model_id_for, + make_model, + provider_model_kwargs, +) + +__all__ = [ + "DEFAULT_LLM_REASONING", + "ModelKwargs", + "fallback_model_id_for", + "make_model", + "provider_model_kwargs", +] diff --git a/agent/runtime/__init__.py b/agent/runtime/__init__.py new file mode 100644 index 00000000..a3f94948 --- /dev/null +++ b/agent/runtime/__init__.py @@ -0,0 +1,25 @@ +from .constants import ( + DEFAULT_LLM_MAX_TOKENS, + DEFAULT_LLM_MODEL_ID, + DEFAULT_RECURSION_LIMIT, + MODEL_CALL_RECURSION_LIMIT, +) +from .execution import graph_loaded_for_execution +from .sandbox import ( + configure_git_identity, + ensure_sandbox_for_thread, + get_cached_sandbox_backend, + recreate_sandbox, +) + +__all__ = [ + "DEFAULT_LLM_MAX_TOKENS", + "DEFAULT_LLM_MODEL_ID", + "DEFAULT_RECURSION_LIMIT", + "MODEL_CALL_RECURSION_LIMIT", + "configure_git_identity", + "ensure_sandbox_for_thread", + "get_cached_sandbox_backend", + "graph_loaded_for_execution", + "recreate_sandbox", +] diff --git a/agent/runtime/constants.py b/agent/runtime/constants.py new file mode 100644 index 00000000..c5f880cd --- /dev/null +++ b/agent/runtime/constants.py @@ -0,0 +1,13 @@ +from agent.server import ( + DEFAULT_LLM_MAX_TOKENS, + DEFAULT_LLM_MODEL_ID, + DEFAULT_RECURSION_LIMIT, + MODEL_CALL_RECURSION_LIMIT, +) + +__all__ = [ + "DEFAULT_LLM_MAX_TOKENS", + "DEFAULT_LLM_MODEL_ID", + "DEFAULT_RECURSION_LIMIT", + "MODEL_CALL_RECURSION_LIMIT", +] diff --git a/agent/runtime/execution.py b/agent/runtime/execution.py new file mode 100644 index 00000000..34389473 --- /dev/null +++ b/agent/runtime/execution.py @@ -0,0 +1,3 @@ +from agent.server import graph_loaded_for_execution + +__all__ = ["graph_loaded_for_execution"] diff --git a/agent/runtime/sandbox.py b/agent/runtime/sandbox.py new file mode 100644 index 00000000..01891449 --- /dev/null +++ b/agent/runtime/sandbox.py @@ -0,0 +1,53 @@ +from collections.abc import Sequence + +from deepagents.backends.protocol import SandboxBackendProtocol + + +async def ensure_sandbox_for_thread( + thread_id: str, + *, + github_proxy_token: str | None = None, + github_proxy_repositories: Sequence[str] | None = None, + repo: dict[str, str] | None = None, +) -> SandboxBackendProtocol: + from agent.server import ensure_sandbox_for_thread as ensure + + return await ensure( + thread_id, + github_proxy_token=github_proxy_token, + github_proxy_repositories=github_proxy_repositories, + repo=repo, + ) + + +def get_cached_sandbox_backend(thread_id: str) -> SandboxBackendProtocol: + # Fork's sync 4-case `__creating__` sentinel lifecycle (see AGENTS.md) handles + # reconnection internally in `ensure_sandbox_for_thread`/`check_or_recreate_sandbox`, + # so unlike upstream's shim there is no caller-supplied `reconnect` callback here: + # fork's `_get_cached_sandbox_backend` is a plain cache lookup. + from agent.server import _get_cached_sandbox_backend as get_backend + + return get_backend(thread_id) + + +async def configure_git_identity(sandbox_backend: SandboxBackendProtocol) -> None: + from agent.server import _configure_git_identity as configure + + await configure(sandbox_backend) + + +async def recreate_sandbox( + thread_id: str, + *, + github_proxy_token: str | None = None, + github_proxy_repositories: Sequence[str] | None = None, + repo: dict[str, str] | None = None, +) -> SandboxBackendProtocol: + from agent.server import _recreate_sandbox as recreate + + return await recreate( + thread_id, + github_proxy_token=github_proxy_token, + github_proxy_repositories=github_proxy_repositories, + repo=repo, + ) diff --git a/langgraph.json b/langgraph.json index 07811c48..38695e77 100644 --- a/langgraph.json +++ b/langgraph.json @@ -3,12 +3,12 @@ "python_version": "3.12", "api_version": "0.10.0rc3", "graphs": { - "agent": "agent.server:traced_agent", - "reviewer": "agent.reviewer:traced_reviewer_agent", - "analyzer": "agent.analyzer:traced_analyzer", - "chat": "agent.chat:traced_chat_agent", - "scheduler": "agent.scheduler:get_scheduler", - "ci_monitor": "agent.ci_monitor:get_ci_monitor" + "agent": "agent.graphs.agent:traced_agent", + "reviewer": "agent.graphs.reviewer:traced_reviewer_agent", + "analyzer": "agent.graphs.analyzer:traced_analyzer", + "chat": "agent.graphs.chat:traced_chat_agent", + "scheduler": "agent.graphs.scheduler:get_scheduler", + "ci_monitor": "agent.graphs.ci_monitor:get_ci_monitor" }, "dependencies": [ "."