mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-09-25 05:56:18 +00:00
* feat(extensions): allow constructor kwargs on config-declared middlewares
extensions.middlewares entries may be a class-path string or {class, kwargs}.
String entries keep the zero-argument constructor. Unknown fields and blank
class paths fail at config validation. Constructor errors still fail at
agent creation.
Fixes #5311
* fix(extensions): coerce middleware kwargs to JSON types
YAML timestamps became datetime objects while JSON kept strings, so
constructors and to_file_dict() json.dump saw different types. Validate
kwargs as JSON types at config load, stringify dates, reject NaN and
other non-JSON values, and cover the raw-dict loader branch.
* style(extensions): wrap middleware Field description for ruff E501
make lint failed: the middlewares description was 289 chars (limit 240).
Wrap it and run ruff format on the two files this PR last touched.
* docs: compact configured middleware guidance to satisfy size limit
---------
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
48 lines
1.9 KiB
Python
48 lines
1.9 KiB
Python
"""Config-declared agent middleware loading."""
|
|
|
|
import logging
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
from langchain.agents.middleware import AgentMiddleware
|
|
|
|
from deerflow.config.extensions_config import ConfiguredMiddlewareSpec
|
|
from deerflow.reflection import resolve_class
|
|
|
|
if TYPE_CHECKING:
|
|
from deerflow.config.app_config import AppConfig
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _middleware_constructor_args(entry: str | ConfiguredMiddlewareSpec | dict[str, Any]) -> tuple[str, dict[str, Any]]:
|
|
"""Return ``(class_path, kwargs)`` for one config entry."""
|
|
if isinstance(entry, str):
|
|
return entry, {}
|
|
if isinstance(entry, ConfiguredMiddlewareSpec):
|
|
return entry.class_path, dict(entry.kwargs)
|
|
parsed = ConfiguredMiddlewareSpec.model_validate(entry)
|
|
return parsed.class_path, dict(parsed.kwargs)
|
|
|
|
|
|
def load_configured_extension_middlewares(app_config: "AppConfig") -> list[AgentMiddleware]:
|
|
"""Instantiate config-declared agent middlewares.
|
|
|
|
Each entry is a ``module.path:ClassName`` string or a
|
|
``ConfiguredMiddlewareSpec`` (``class`` plus optional ``kwargs``).
|
|
Import, attribute, and subclass validation intentionally go through the
|
|
shared reflection resolver so failures carry the same actionable
|
|
dependency hints as models, tools, sandbox providers, and guardrail
|
|
providers. Constructor errors fail loudly at agent creation.
|
|
"""
|
|
middlewares: list[AgentMiddleware] = []
|
|
for entry in list(app_config.extensions.middlewares or []):
|
|
class_path, kwargs = _middleware_constructor_args(entry)
|
|
middleware_cls = resolve_class(class_path, AgentMiddleware)
|
|
try:
|
|
middleware = middleware_cls(**kwargs)
|
|
except Exception:
|
|
logger.exception("Failed to instantiate configured extension middleware %s", class_path)
|
|
raise
|
|
middlewares.append(middleware)
|
|
return middlewares
|