mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-28 22:20:35 +00:00
* feat(examples): add opt-in fetched-content screening extension * fix(examples): screen sync and async results through supported middleware hooks * fix(examples): preserve empty message IDs when applying screening warnings * fix(examples): include screening policy in assembly identity * feat(examples): load fetched-content screening through the extension entry Package the screening example as a plugins: extension instead of an operator-configured middleware. install() validates the private config and, once enabled, contributes one TOOL_VISIBLE middleware for lead agents and subagents. The package imports only deerflow_extension_api. Extension tool wrappers are observational, so detection and the warning use two supported contracts: the tool wrapper classifies the visible result and records flagged tool-call IDs in the run's task store, and before_model replaces the matching messages of the latest tool step by ID. The excerpt sent to Jev is now the redacted, sanitized text the model sees. Runs without a task store send nothing. Unexpected local errors surface as isolation diagnostics; provider errors fail open. Tests load the package through load_extensions() and the host isolation wrapper and run real lead/subagent graphs with a task store bound as the Gateway worker binds it. The README records what the example exercised in the extension API and the gaps it found. * fix(examples): classify each tool message of a screened result on its own A Command result was classified as one concatenated excerpt and the flag landed on its first text message, so a benign first result could take the warning while an injected later result reached the model unmarked. Each text message now gets its own bounded excerpt and Jev request, for at most eight messages per tool call. The requests share one client and run concurrently in a task group, each under its own deadline, so one slow or failed request cannot hide another message's flag. Every flagged message's tool-call ID is recorded. The message cap joins the declared policy, and the README describes the per-message requests and data sharing. --------- Co-authored-by: Totoro-qaq <279883115+Totoro-qaq@users.noreply.github.com>
40 lines
1.5 KiB
Python
40 lines
1.5 KiB
Python
"""Advisory screening of fetched content, contributed through the extension API."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Mapping, Sequence
|
|
from typing import Any
|
|
|
|
from deerflow_extension_api import AgentBuildContext, AgentScope, ExtensionData, ExtensionInstall, ExtensionRegistry, MiddlewarePlacement, Placement, extension
|
|
|
|
from .screener import Options, ScreeningMiddleware
|
|
|
|
__all__ = ["ScreeningMiddleware", "install"]
|
|
|
|
|
|
class _Contributor:
|
|
def __init__(self, options: Options) -> None:
|
|
self._options = options
|
|
|
|
def contribute_middlewares(self, app_store: ExtensionData, ctx: AgentBuildContext) -> Sequence[MiddlewarePlacement]:
|
|
# TOOL_VISIBLE is outer of the host's truncation, sanitization, PII
|
|
# redaction and error wrapping: the excerpt is what the model sees.
|
|
return (MiddlewarePlacement(ScreeningMiddleware(self._options), Placement.TOOL_VISIBLE, AgentScope.BOTH),)
|
|
|
|
|
|
@extension(api="0.2.3", name="jev-screening")
|
|
def install(registry: ExtensionRegistry, config: Mapping[str, Any]) -> None:
|
|
"""Contribute the screening middleware once the operator opts in.
|
|
|
|
``enabled: true`` in the private configuration is also the consent to send
|
|
excerpts to the configured TypeSafe endpoint, so the default contributes
|
|
nothing. Invalid settings raise, which the loader reports as a diagnostic.
|
|
"""
|
|
options = Options.model_validate(dict(config))
|
|
if not options.enabled:
|
|
return
|
|
registry.middlewares(_Contributor(options))
|
|
|
|
|
|
_entry_point: ExtensionInstall = install
|