From 2851539b708a05b7051433356124472307846f63 Mon Sep 17 00:00:00 2001 From: mschoi Date: Mon, 26 Oct 2026 17:58:06 +0900 Subject: [PATCH] feat(agent): register blue_cell as a decepticon subagent (purple loop) The red orchestrator dispatches blue_cell as a subagent when the AutoBot package is installed (decepticon[blue]): the SUBAGENT_SPEC moves from the removed Decepticon in-tree module, declared here under the decepticon.subagents entry-point (parent_agents pinned to decepticon, bundle standard, priority 90). Verified discoverable via importlib.metadata alongside the agents entry-point. --- packages/autobot/autobot/agent/blue_cell.py | 20 ++++++++++++++++++- packages/autobot/pyproject.toml | 5 +++++ uv.lock | 22 ++++++++++----------- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/packages/autobot/autobot/agent/blue_cell.py b/packages/autobot/autobot/agent/blue_cell.py index 8fe0062..4e19bbc 100644 --- a/packages/autobot/autobot/agent/blue_cell.py +++ b/packages/autobot/autobot/agent/blue_cell.py @@ -33,13 +33,14 @@ from autobot.agent.middleware.prompt_injection_shield import PromptInjectionShieldMiddleware from autobot.agent.middleware.untrusted_output import UntrustedOutputMiddleware from autobot.agent.models import build_model -from autobot.agent.tools.blue_sensor import ( +from autobot.agent.tools.blue_sensor import ( # noqa: F401 — re-exported for the spec blue_sensor_body, blue_sensor_events, blue_sensor_scan, blue_sensor_search, blue_sensor_timeline, ) +from decepticon_core.plugin_loader import SubAgentSpec _ROLE = "blue_cell" _RECURSION_LIMIT = 120 @@ -108,6 +109,23 @@ def create_blue_cell_agent( ).with_config({"recursion_limit": recursion_limit or _RECURSION_LIMIT}) +# The red orchestrator dispatches blue_cell as a subagent (the purple loop): +# discovered via the ``decepticon.subagents`` entry-point declared in this +# package's metadata. parent_agents pins it to the ``decepticon`` main agent. +SUBAGENT_SPEC = SubAgentSpec( + name="blue_cell", + description=( + "Blue Cell — independent read-only defender. Investigates live local " + "target telemetry and the always-on monitor's incidents, then reports " + "evidence and uncertainty. No bash or containment tools." + ), + factory=create_blue_cell_agent, + parent_agents=("decepticon",), + bundle="standard", + priority=90, +) + + def __getattr__(name: str): # Module-level lazy graph attribute — the Decepticon graph registry's # ``decepticon.agents`` discovery contract requires a module-level diff --git a/packages/autobot/pyproject.toml b/packages/autobot/pyproject.toml index 4abffe2..913d6d8 100644 --- a/packages/autobot/pyproject.toml +++ b/packages/autobot/pyproject.toml @@ -75,6 +75,11 @@ opensearch = "autobot.stores.opensearch_store:OpenSearchEventStore" [project.entry-points."decepticon.agents"] blue_cell = "autobot.agent.blue_cell:graph" +# The red orchestrator dispatches blue_cell as a subagent when this package +# is installed (``decepticon[blue]``) — the purple loop's defender side. +[project.entry-points."decepticon.subagents"] +blue_cell = "autobot.agent.blue_cell:SUBAGENT_SPEC" + [project.urls] Homepage = "https://github.com/BitterSecurity/AutoBot" Repository = "https://github.com/BitterSecurity/AutoBot" diff --git a/uv.lock b/uv.lock index f5bee33..26b4056 100644 --- a/uv.lock +++ b/uv.lock @@ -9,7 +9,7 @@ resolution-markers = [ [manifest] members = [ "autobot-workspace", - "bittersecurity-autobot", + "bs-autobot", ] [[package]] @@ -73,7 +73,16 @@ dev = [ ] [[package]] -name = "bittersecurity-autobot" +name = "bracex" +version = "3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/37/adf8dd2cde958c2d086bdd87fc36b532fd824bf38f10be6348d65da0c8f9/bracex-3.2.tar.gz", hash = "sha256:0a3d40bfae4caae4d3bfd0ea715874799fab711c38fd4012cc35343e815405cd", size = 29771, upload-time = "2026-10-22T00:28:49.508Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/65/8030b03de8137d1aab7dd6ecfecdba2fc22fc849fa35959b024f62293a99/bracex-3.2-py3-none-any.whl", hash = "sha256:8f3e908a452f66707e1d6d91b3d7d7d4c649d248df18537c0dc710aeb9c30d87", size = 12019, upload-time = "2026-10-22T00:28:48.233Z" }, +] + +[[package]] +name = "bs-autobot" version = "0.0.0" source = { editable = "packages/autobot" } dependencies = [ @@ -114,15 +123,6 @@ requires-dist = [ ] provides-extras = ["opensearch", "testing"] -[[package]] -name = "bracex" -version = "3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fb/37/adf8dd2cde958c2d086bdd87fc36b532fd824bf38f10be6348d65da0c8f9/bracex-3.2.tar.gz", hash = "sha256:0a3d40bfae4caae4d3bfd0ea715874799fab711c38fd4012cc35343e815405cd", size = 29771, upload-time = "2026-10-22T00:28:49.508Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/65/8030b03de8137d1aab7dd6ecfecdba2fc22fc849fa35959b024f62293a99/bracex-3.2-py3-none-any.whl", hash = "sha256:8f3e908a452f66707e1d6d91b3d7d7d4c649d248df18537c0dc710aeb9c30d87", size = 12019, upload-time = "2026-10-22T00:28:48.233Z" }, -] - [[package]] name = "certifi" version = "2026.10.23"