From 25106cdcd2bfdbddb877b6c22caeb48acaad0210 Mon Sep 17 00:00:00 2001 From: Nick Bobrowski <39348559+nicko-ai@users.noreply.github.com> Date: Thu, 11 Jun 2026 18:08:16 +0100 Subject: [PATCH] chore: remove redundant Agency Swarm patches - drop dual communication monkey patch now covered by agency-swarm 1.10 - drop file attachment reference patch now covered by Agency Swarm FastAPI file_urls context - keep remaining OpenSwarm-only runtime patches --- patches/patch_agency_swarm_dual_comms.py | 262 ----------------------- patches/patch_file_attachment_refs.py | 115 ---------- scripts/smoke-bootstrap-onboard.py | 8 - swarm.py | 4 - 4 files changed, 389 deletions(-) delete mode 100644 patches/patch_agency_swarm_dual_comms.py delete mode 100644 patches/patch_file_attachment_refs.py diff --git a/patches/patch_agency_swarm_dual_comms.py b/patches/patch_agency_swarm_dual_comms.py deleted file mode 100644 index 1088447b..00000000 --- a/patches/patch_agency_swarm_dual_comms.py +++ /dev/null @@ -1,262 +0,0 @@ -#!/usr/bin/env python3 -""" -Runtime monkey patch for Agency Swarm dual communication tools per pair. - -This patches classes/functions in memory (no framework file rewriting): -- agency.setup.parse_agent_flows -- agency.setup.configure_agents -- agency.core.parse_agent_flows -- agency.core.configure_agents -""" - -from __future__ import annotations - -from typing import Any - - -def _validate_communication_tool_class(tool_class: type, send_message_class: type, handoff_class: type) -> None: - if not issubclass(tool_class, (send_message_class, handoff_class)): - raise TypeError( - f"Invalid communication tool class: {tool_class.__name__}. " - "Expected a SendMessage or Handoff subclass." - ) - - -def _add_tool_class_for_pair( - mapping: dict[tuple[str, str], list[type]], - default_tool_pairs: set[tuple[str, str]], - pair_key: tuple[str, str], - tool_class: type | None, - send_message_class: type, - handoff_class: type, -) -> None: - if tool_class is None: - return - _validate_communication_tool_class(tool_class, send_message_class, handoff_class) - if pair_key in default_tool_pairs and issubclass(tool_class, send_message_class): - raise ValueError( - f"Duplicate communication tool class detected for {pair_key[0]} -> {pair_key[1]}: " - f"{tool_class.__name__}. Each SendMessage tool for a pair can only be defined once." - ) - classes = mapping.setdefault(pair_key, []) - if issubclass(tool_class, send_message_class): - for existing_tool_class in classes: - if issubclass(existing_tool_class, send_message_class): - raise ValueError( - f"Duplicate communication tool class detected for {pair_key[0]} -> {pair_key[1]}: " - f"{tool_class.__name__}. Each SendMessage tool for a pair can only be defined once." - ) - if tool_class in classes: - raise ValueError( - f"Duplicate communication tool class detected for {pair_key[0]} -> {pair_key[1]}: " - f"{tool_class.__name__}. Each tool class for a pair can only be defined once." - ) - classes.append(tool_class) - - -def _add_default_tool_pair( - custom_mapping: dict[tuple[str, str], list[type]], - default_tool_pairs: set[tuple[str, str]], - pair_key: tuple[str, str], - send_message_class: type, -) -> None: - if pair_key in default_tool_pairs: - raise ValueError( - f"Duplicate communication flow detected: {pair_key[0]} -> {pair_key[1]}. " - "Each default agent-to-agent communication can only be defined once." - ) - for tool_class in custom_mapping.get(pair_key, []): - if issubclass(tool_class, send_message_class): - raise ValueError( - f"Duplicate communication tool class detected for {pair_key[0]} -> {pair_key[1]}: " - f"{tool_class.__name__}. Each SendMessage tool for a pair can only be defined once." - ) - default_tool_pairs.add(pair_key) - - -def apply_dual_comms_patch() -> None: - import warnings - - from agency_swarm.agent.agent_flow import AgentFlow - from agency_swarm.agent.core import Agent - from agency_swarm.agency import core as core_mod - from agency_swarm.agency import setup as setup_mod - from agency_swarm.tools.send_message import Handoff, SendMessage, SendMessageHandoff - - if getattr(setup_mod, "_dual_comms_patch_applied", False): - return - - def parse_agent_flows_patched( - agency: Any, communication_flows: list[Any] - ) -> tuple[list[tuple[Agent, Agent]], dict[tuple[str, str], list[type]], set[tuple[str, str]]]: - basic_flows: list[tuple[Agent, Agent]] = [] - tool_class_mapping: dict[tuple[str, str], list[type]] = {} - default_tool_pairs: set[tuple[str, str]] = set() - seen_flows: set[tuple[str, str]] = set() - - chain_flows = AgentFlow.get_and_clear_chain_flows() - chain_flows_used = False - - for flow_entry in communication_flows: - if isinstance(flow_entry, AgentFlow): - flow_entry = (flow_entry, None) - - if isinstance(flow_entry, (tuple, list)) and len(flow_entry) == 2: - first, second = flow_entry - - if isinstance(first, Agent) and isinstance(second, Agent): - flow_key = (first.name, second.name) - if flow_key not in seen_flows: - seen_flows.add(flow_key) - basic_flows.append((first, second)) - _add_default_tool_pair(tool_class_mapping, default_tool_pairs, flow_key, SendMessage) - - elif isinstance(first, AgentFlow) and (isinstance(second, type) or second is None): - tool_class = second - direct_flows = first.get_all_flows() - if not chain_flows_used: - all_flows = direct_flows + [f for f in chain_flows if f not in direct_flows] - chain_flows_used = True - else: - all_flows = direct_flows - - for sender, receiver in all_flows: - flow_key = (sender.name, receiver.name) - if flow_key not in seen_flows: - seen_flows.add(flow_key) - basic_flows.append((sender, receiver)) - elif tool_class is None: - _add_default_tool_pair(tool_class_mapping, default_tool_pairs, flow_key, SendMessage) - continue - if tool_class is None: - _add_default_tool_pair(tool_class_mapping, default_tool_pairs, flow_key, SendMessage) - else: - _add_tool_class_for_pair( - tool_class_mapping, - default_tool_pairs, - flow_key, - tool_class, - SendMessage, - Handoff, - ) - else: - raise TypeError( - f"Invalid communication flow entry: {flow_entry}. " - "Expected (Agent, Agent) or (AgentFlow, tool_class)." - ) - - elif isinstance(flow_entry, (tuple, list)) and len(flow_entry) == 3: - sender, receiver, tool_class = flow_entry - - if not isinstance(sender, Agent) or not isinstance(receiver, Agent): - raise TypeError(f"Invalid communication flow entry: {flow_entry}. Expected (Agent, Agent, tool_class).") - - # The agency factory reconstructs flows from _communication_tool_classes, - # which stores lists of types per pair. Accept both a single class and a list. - tool_classes = tool_class if isinstance(tool_class, (list, tuple)) else [tool_class] - if not tool_classes: - raise ValueError("Communication flow tool class list cannot be empty.") - for tc in tool_classes: - if not isinstance(tc, type): - raise TypeError(f"Invalid tool class in communication flow: {tc}. Expected a class type.") - - flow_key = (sender.name, receiver.name) - if flow_key not in seen_flows: - seen_flows.add(flow_key) - basic_flows.append((sender, receiver)) - - for tc in tool_classes: - _add_tool_class_for_pair(tool_class_mapping, default_tool_pairs, flow_key, tc, SendMessage, Handoff) - - else: - raise ValueError(f"Invalid communication flow entry: {flow_entry}. Expected 2 or 3 elements.") - - return basic_flows, tool_class_mapping, default_tool_pairs - - def configure_agents_patched(agency: Any, defined_communication_flows: list[tuple[Agent, Agent]]) -> None: - setup_mod.logger.info("Configuring agents...") - - communication_map: dict[str, list[str]] = {agent_name: [] for agent_name in agency.agents} - for sender, receiver in defined_communication_flows: - sender_name = sender.name - receiver_name = receiver.name - if receiver_name not in communication_map[sender_name]: - communication_map[sender_name].append(receiver_name) - - for agent_name, agent_instance in agency.agents.items(): - runtime_state = agency._agent_runtime_state[agent_name] - allowed_recipients = communication_map.get(agent_name, []) - - if allowed_recipients: - if not agent_instance.supports_outbound_communication: - joined = ", ".join(allowed_recipients) - raise ValueError( - f"Agent '{agent_name}' cannot be the sender in communication_flows. " - f"It can receive delegated work, but it cannot delegate to: {joined}." - ) - setup_mod.logger.debug(f"Agent '{agent_name}' can send messages to: {allowed_recipients}") - for recipient_name in allowed_recipients: - recipient_agent = agency.agents[recipient_name] - pair_key = (agent_name, recipient_name) - configured = agency._communication_tool_classes.get(pair_key, []) - tool_classes: list[type] = [] - if pair_key in agency._default_communication_tool_pairs: - tool_classes.append(agency.send_message_tool_class or SendMessage) - tool_classes.extend(configured) - if not tool_classes: - tool_classes.append(agency.send_message_tool_class or SendMessage) - - for effective_tool_class in tool_classes: - try: - if isinstance(effective_tool_class, Handoff) or ( - isinstance(effective_tool_class, type) and issubclass(effective_tool_class, Handoff) - ): - if ( - not setup_mod._warned_deprecated_send_message_handoff - and isinstance(effective_tool_class, type) - and issubclass(effective_tool_class, SendMessageHandoff) - ): - warnings.warn( - "SendMessageHandoff is deprecated; use Handoff instead.", - DeprecationWarning, - stacklevel=3, - ) - setup_mod._warned_deprecated_send_message_handoff = True - - handoff_instance = effective_tool_class().create_handoff(recipient_agent=recipient_agent) - handoff_instance._agency_swarm_tool_class = effective_tool_class - runtime_state.handoffs.append(handoff_instance) - setup_mod.logger.debug(f"Added Handoff for {agent_name} -> {recipient_name}") - else: - chosen_tool_class = effective_tool_class or SendMessage - if not isinstance(chosen_tool_class, type) or not issubclass(chosen_tool_class, SendMessage): - chosen_tool_class = SendMessage - - agent_instance.register_subagent( - recipient_agent, - send_message_tool_class=chosen_tool_class, - runtime_state=runtime_state, - ) - except Exception as e: - setup_mod.logger.error( - f"Error registering subagent '{recipient_name}' for sender '{agent_name}': {e}", - exc_info=True, - ) - else: - setup_mod.logger.debug(f"Agent '{agent_name}' has no explicitly defined outgoing communication paths.") - - setup_mod.logger.info("Agent configuration complete.") - - setup_mod.parse_agent_flows = parse_agent_flows_patched - setup_mod.configure_agents = configure_agents_patched - - # Agency.__init__ uses these symbols imported into core module scope. - core_mod.parse_agent_flows = parse_agent_flows_patched - core_mod.configure_agents = configure_agents_patched - - setup_mod._dual_comms_patch_applied = True - - -if __name__ == "__main__": - apply_dual_comms_patch() - print("Dual communication monkey patch applied in current Python process.") diff --git a/patches/patch_file_attachment_refs.py b/patches/patch_file_attachment_refs.py deleted file mode 100644 index 6ad3d2df..00000000 --- a/patches/patch_file_attachment_refs.py +++ /dev/null @@ -1,115 +0,0 @@ -""" -Patch: inject attachment file references into the user message. -""" - -import asyncio - -_PATCH_APPLIED = False - - -def apply_file_attachment_reference_patch() -> None: - global _PATCH_APPLIED - if _PATCH_APPLIED: - return - _PATCH_APPLIED = True - _patch_endpoint_handler_factories() - - -def _build_attachment_note(file_urls: dict[str, str]) -> str: - lines = [ - "\n\n[SYSTEM NOTE] The user attached the following files.", - "Use ONLY the URLs below as file references in your tools (e.g. as `input_image_ref`).", - "Any /mnt/data/ paths you see are internal OpenAI server paths — they are NOT real local paths and must NOT be used or shown to the user:", - ] - for filename, ref in file_urls.items(): - lines.append(f" - {filename}: {ref}") - return "\n".join(lines) - - -def _patch_endpoint_handler_factories() -> None: - from fastapi import Depends - from fastapi import Request as FastAPIRequest - from agency_swarm.integrations.fastapi_utils import endpoint_handlers as eh - - _original_make_response = eh.make_response_endpoint - _original_make_stream = eh.make_stream_endpoint - _original_make_agui = eh.make_agui_chat_endpoint - - def patched_make_response_endpoint(request_model, agency_factory, verify_token, allowed_local_dirs=None): - original_handler = _original_make_response(request_model, agency_factory, verify_token, allowed_local_dirs) - - async def handler(request: request_model, token: str = Depends(verify_token)): - if getattr(request, "file_urls", None): - note = _build_attachment_note(request.file_urls) - existing = getattr(request, "additional_instructions", None) or "" - request = request.model_copy(update={"additional_instructions": (existing + "\n\n" + note).strip()}) - return await original_handler(request, token) - - return handler - - def patched_make_stream_endpoint(request_model, agency_factory, verify_token, run_registry, allowed_local_dirs=None): - original_handler = _original_make_stream(request_model, agency_factory, verify_token, run_registry, allowed_local_dirs) - - async def handler(http_request: FastAPIRequest, request: request_model, token: str = Depends(verify_token)): - if getattr(request, "file_urls", None): - note = _build_attachment_note(request.file_urls) - existing = getattr(request, "additional_instructions", None) or "" - request = request.model_copy(update={"additional_instructions": (existing + "\n\n" + note).strip()}) - response = await original_handler(http_request, request, token) - body_iterator = getattr(response, "body_iterator", None) - if body_iterator is not None: - response.body_iterator = _with_sse_heartbeats(body_iterator) - return response - - return handler - - def patched_make_agui_endpoint(request_model, agency_factory, verify_token, allowed_local_dirs=None): - original_handler = _original_make_agui(request_model, agency_factory, verify_token, allowed_local_dirs) - - async def handler(request: request_model, token: str = Depends(verify_token)): - if getattr(request, "file_urls", None): - note = _build_attachment_note(request.file_urls) - existing = getattr(request, "additional_instructions", None) or "" - request = request.model_copy(update={"additional_instructions": (existing + "\n\n" + note).strip()}) - return await original_handler(request, token) - - return handler - - eh.make_response_endpoint = patched_make_response_endpoint - eh.make_stream_endpoint = patched_make_stream_endpoint - eh.make_agui_chat_endpoint = patched_make_agui_endpoint - - -async def _with_sse_heartbeats(body_iterator, interval_seconds: float = 10.0): - queue: asyncio.Queue = asyncio.Queue() - sentinel = object() - - async def produce() -> None: - try: - async for chunk in body_iterator: - await queue.put(chunk) - except BaseException as exc: - await queue.put(exc) - finally: - await queue.put(sentinel) - - producer = asyncio.create_task(produce()) - try: - while True: - try: - item = await asyncio.wait_for(queue.get(), timeout=interval_seconds) - except TimeoutError: - yield b": openswarm heartbeat\n\n" - continue - if item is sentinel: - break - if isinstance(item, BaseException): - raise item - yield item - finally: - if not producer.done(): - producer.cancel() - try: - await producer - except asyncio.CancelledError: - pass diff --git a/scripts/smoke-bootstrap-onboard.py b/scripts/smoke-bootstrap-onboard.py index a95db55f..f19931e8 100644 --- a/scripts/smoke-bootstrap-onboard.py +++ b/scripts/smoke-bootstrap-onboard.py @@ -59,14 +59,6 @@ def smoke_swarm_import_skips_bootstrap() -> None: set_tracing_export_api_key=lambda _value: order.append("agents"), ), "patches": patches, - "patches.patch_agency_swarm_dual_comms": module( - "patches.patch_agency_swarm_dual_comms", - apply_dual_comms_patch=lambda: order.append("patch"), - ), - "patches.patch_file_attachment_refs": module( - "patches.patch_file_attachment_refs", - apply_file_attachment_reference_patch=lambda: order.append("patch"), - ), "patches.patch_ipython_interpreter_composio": module( "patches.patch_ipython_interpreter_composio", apply_ipython_composio_context_patch=lambda: order.append("patch"), diff --git a/swarm.py b/swarm.py index eade786e..3cb6d971 100644 --- a/swarm.py +++ b/swarm.py @@ -12,8 +12,6 @@ def _configure_runtime() -> None: from dotenv import load_dotenv from agents import set_tracing_disabled, set_tracing_export_api_key - from patches.patch_agency_swarm_dual_comms import apply_dual_comms_patch - from patches.patch_file_attachment_refs import apply_file_attachment_reference_patch from patches.patch_ipython_interpreter_composio import ( apply_ipython_composio_context_patch, ) @@ -22,8 +20,6 @@ def _configure_runtime() -> None: load_dotenv(dotenv_path=_openswarm_state_root() / ".env") apply_utf8_file_read_patch() - apply_dual_comms_patch() - apply_file_attachment_reference_patch() apply_ipython_composio_context_patch() _tracing_key = os.getenv("OPENAI_API_KEY")