open-swe/agent/utils/deferred_model.py
amoussa1229 25d4886b9a feat: port durable dispatch hardening and startup latency improvements
Port five upstream PRs onto dev:

- #1621 / #1658: durable dispatch with loopback webhook defense,
  create_durable_run helper, _config_with_prepare_run_id, degradation
  to None for relative/loopback completion webhook URLs
- #1696: run-level completion webhook deduplication (replace
  claim-then-post with post-then-flag per run_id), DeferredErrorModel
  for graph-factory resilience, ToolRetryMiddleware for task subagents,
  TimeoutWrapupMiddleware for all three graphs
- #1697: lazy-load __init__.py for agent.middleware, agent.tools,
  agent.dashboard (PEP 562); defer heavy imports (exa_py in web_search,
  agent.webapp in request_pr_review, deepagents in sandbox.py); add
  ttl_cache.py with stale-while-revalidate for tool loaders

Refs: #137
2026-07-09 17:29:17 +00:00

57 lines
1.9 KiB
Python

from __future__ import annotations
import logging
from typing import Any
from langchain_core.language_models import BaseChatModel
from .model import make_model
logger = logging.getLogger(__name__)
class DeferredErrorModel(BaseChatModel):
"""Model placeholder that raises a stored setup error on first invocation."""
error_message: str
model_id: str | None = None
@property
def _llm_type(self) -> str:
return "deferred-error"
def _get_ls_params(self, stop: Any = None, **kwargs: Any) -> dict[str, Any]:
params = super()._get_ls_params(stop=stop, **kwargs)
if self.model_id:
params["ls_model_name"] = self.model_id
if ":" in self.model_id:
params["ls_provider"] = self.model_id.split(":", 1)[0]
return params
def bind_tools(self, tools: Any, **kwargs: Any) -> DeferredErrorModel:
return self
def _generate(self, messages: Any, stop: Any = None, run_manager: Any = None, **kwargs: Any):
raise ValueError(self.error_message)
def make_deferred_error_model(
error: BaseException, *, model_id: str | None = None
) -> BaseChatModel:
return DeferredErrorModel(error_message=f"{type(error).__name__}: {error}", model_id=model_id)
def make_model_or_defer(model_id: str, **kwargs: Any) -> BaseChatModel:
"""Call ``make_model`` and wrap any setup error in a ``DeferredErrorModel``.
This lets graph factories pass a model placeholder into the agent graph on
startup without crashing the process. The error is raised later inside the
agent run when the model is first invoked, so the caller can recover
gracefully (e.g. via fallback middleware or by surfacing the error to the
user).
"""
try:
return make_model(model_id, **kwargs)
except Exception as e: # noqa: BLE001
logger.warning("Deferring model setup failure for %s", model_id, exc_info=True)
return make_deferred_error_model(e, model_id=model_id)