open-swe/agent/middleware/refresh_github_proxy.py
Johannes du Plessis da20e57bcc
fix: refresh sandbox GitHub proxy token before mid-run expiry (#1496)
* fix: refresh sandbox GitHub proxy token before mid-run expiry

GitHub App installation tokens expire after exactly 1 hour. The LangSmith
sandbox proxy was configured once at run start with a snapshot of that
token, so runs longer than ~1h hit 401s on every gh/git call. Record the
proxy token's expiry per thread and add a before-model hook that
re-configures the proxy with a fresh token when it nears expiry.

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>

* fix: preserve repo-scoped proxy token on mid-run refresh

Reviewer runs mint a repository-scoped installation token. Record the
repo scope per thread alongside the expiry so the before-model refresh
re-mints a token with the same scope instead of an installation-wide
token, avoiding privilege expansion on long reviewer runs.

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>

* fix: update passthrough stub for github_proxy_repositories param

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-11 10:59:21 -07:00

47 lines
1.4 KiB
Python

"""Before-model middleware that keeps the sandbox GitHub proxy token fresh.
The LangSmith sandbox proxy is configured with a GitHub App installation token
that expires after exactly one hour. Long runs would otherwise hit 401s on
every ``gh``/``git`` call once that snapshot goes stale. This hook re-configures
the proxy with a fresh token before each model call when the recorded token is
near expiry.
"""
from __future__ import annotations
import logging
from typing import Any
from langchain.agents.middleware import AgentState, before_model
from langgraph.config import get_config
from langgraph.runtime import Runtime
from ..utils.github_proxy import maybe_refresh_proxy_token
logger = logging.getLogger(__name__)
@before_model
async def refresh_github_proxy_before_model(
state: AgentState, # noqa: ARG001
runtime: Runtime, # noqa: ARG001
) -> dict[str, Any] | None:
"""Refresh the sandbox proxy's GitHub token before it expires mid-run."""
try:
config = get_config()
thread_id = config.get("configurable", {}).get("thread_id")
except Exception: # noqa: BLE001
return None
if not thread_id:
return None
try:
await maybe_refresh_proxy_token(thread_id)
except Exception: # noqa: BLE001
logger.warning(
"Failed to refresh GitHub proxy token for thread %s",
thread_id,
exc_info=True,
)
return None