From 8860190398e8d7cbb2b7b89912f2296a49415c9e Mon Sep 17 00:00:00 2001 From: Nick Bobrowski <39348559+nicko-ai@users.noreply.github.com> Date: Sat, 30 May 2026 00:02:29 +0100 Subject: [PATCH 1/3] fix: align OpenSwarm Python startup entry - Route python swarm.py through the configured OpenSwarm launcher path. - Set the Python product profile entry file to swarm.py. - Remove stale agency.py packaging metadata and sync requirements with pyproject. - Extend startup smoke coverage for script delegation and product entry configuration. --- pyproject.toml | 2 +- requirements.txt | 6 ++++-- run_utils.py | 1 + scripts/smoke-bootstrap-onboard.py | 32 ++++++++++++++++++++++++++++-- swarm.py | 19 +++++------------- 5 files changed, 41 insertions(+), 19 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index eeeee0a0..b5b907c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,7 @@ dependencies = [ openswarm = "run_utils:main" [tool.setuptools] -py-modules = ["agency", "swarm", "helpers", "config", "onboard", "server", "run_utils"] +py-modules = ["swarm", "helpers", "config", "onboard", "server", "run_utils"] [tool.setuptools.packages.find] where = ["."] diff --git a/requirements.txt b/requirements.txt index 77db5c33..ca1bf4e0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,7 @@ -agency-swarm[fastapi,jupyter,litellm]>=1.9.7 +agency-swarm[fastapi,jupyter,litellm]>=1.9.8 questionary>=2.0.0 +python-dotenv +rich fastapi uvicorn composio==0.8.0 @@ -28,6 +30,7 @@ nbformat>=5.0.0 # Image processing (for load_images tool) pillow>=9.0.0 +opencv-python-headless # PowerPoint processing (for slides_agent) python-pptx>=1.0.0 @@ -43,7 +46,6 @@ cairosvg weasyprint html2text google-genai -opencv-python-headless moviepy<2 fal-client httpx diff --git a/run_utils.py b/run_utils.py index 02b90a67..1593142e 100644 --- a/run_utils.py +++ b/run_utils.py @@ -60,6 +60,7 @@ def _load_openswarm_dotenv(*, override: bool = False) -> bool: def _configure_product_env() -> None: os.environ.setdefault("AGENTSWARM_PRODUCT_SKIP_POST_AUTH_MODEL_SELECTION", "true") + os.environ.setdefault("AGENTSWARM_PRODUCT_ENTRY_FILES", "swarm.py") os.environ.setdefault("AGENTSWARM_PRODUCT_TUI_LOGO_LEFT", _PRODUCT_TUI_LOGO_LEFT) os.environ.setdefault("AGENTSWARM_PRODUCT_TUI_LOGO_RIGHT", _PRODUCT_TUI_LOGO_RIGHT) os.environ.setdefault("AGENTSWARM_PRODUCT_WORDMARK_LINES", _PRODUCT_WORDMARK_LINES) diff --git a/scripts/smoke-bootstrap-onboard.py b/scripts/smoke-bootstrap-onboard.py index c9317922..9ec3523e 100644 --- a/scripts/smoke-bootstrap-onboard.py +++ b/scripts/smoke-bootstrap-onboard.py @@ -7,6 +7,7 @@ import io import json import os +import runpy import sys import tempfile import types @@ -48,9 +49,7 @@ def smoke_swarm_import_skips_bootstrap() -> None: replacements = { "run_utils": module( "run_utils", - _bootstrap=lambda: order.append("bootstrap"), _openswarm_state_root=lambda: ROOT, - _preload_agentswarm_bin=lambda: order.append("preload"), ), "dotenv": module("dotenv", load_dotenv=lambda *args, **kwargs: order.append("dotenv")), "agents": module( @@ -97,6 +96,27 @@ def smoke_swarm_import_skips_bootstrap() -> None: raise RuntimeError(f"swarm.py did not configure runtime during import: {order}") +def smoke_swarm_script_delegates_to_run_utils_main() -> None: + calls: list[str] = [] + replacements = { + "run_utils": module( + "run_utils", + _openswarm_state_root=lambda: ROOT, + main=lambda: calls.append("main"), + ), + } + old_path = list(sys.path) + try: + with swapped_modules(replacements): + sys.path.insert(0, str(ROOT)) + runpy.run_path(str(ROOT / "swarm.py"), run_name="__main__") + finally: + sys.path[:] = old_path + + if calls != ["main"]: + raise RuntimeError(f"python swarm.py did not delegate to run_utils.main: {calls}") + + def smoke_onboard_env_writes() -> None: sys.path.insert(0, str(ROOT)) try: @@ -167,6 +187,7 @@ def smoke_product_state_root_env() -> None: encoding="utf-8", ) old_state = os.environ.pop("AGENTSWARM_PRODUCT_STATE_ROOT", None) + old_entry = os.environ.pop("AGENTSWARM_PRODUCT_ENTRY_FILES", None) old_bin = os.environ.pop("AGENTSWARM_BIN", None) old_key = os.environ.pop("OPENAI_API_KEY", None) old_cwd = Path.cwd() @@ -187,6 +208,8 @@ def smoke_product_state_root_env() -> None: if os.environ.get("AGENTSWARM_PRODUCT_STATE_ROOT") != str(root): raise RuntimeError("OpenSwarm did not configure AGENTSWARM_PRODUCT_STATE_ROOT from OPENSWARM_STATE_ROOT") + if os.environ.get("AGENTSWARM_PRODUCT_ENTRY_FILES") != "swarm.py": + raise RuntimeError("OpenSwarm Python path did not configure swarm.py as the product entry file") if os.environ.get("OPENAI_API_KEY") != "state-openai": raise RuntimeError("OpenSwarm did not load dotenv values from the fixed state root before caller cwd") if os.environ.get("AGENTSWARM_BIN") != "/explicit/bin": @@ -219,6 +242,10 @@ def smoke_product_state_root_env() -> None: os.environ.pop("AGENTSWARM_PRODUCT_STATE_ROOT", None) else: os.environ["AGENTSWARM_PRODUCT_STATE_ROOT"] = old_state + if old_entry is None: + os.environ.pop("AGENTSWARM_PRODUCT_ENTRY_FILES", None) + else: + os.environ["AGENTSWARM_PRODUCT_ENTRY_FILES"] = old_entry if old_bin is None: os.environ.pop("AGENTSWARM_BIN", None) else: @@ -395,6 +422,7 @@ def which(name: str) -> str | None: def main() -> int: smoke_swarm_import_skips_bootstrap() + smoke_swarm_script_delegates_to_run_utils_main() smoke_onboard_env_writes() smoke_product_state_root_env() smoke_bootstrap_node_setup_installs_slides_dependencies() diff --git a/swarm.py b/swarm.py index eade786e..9c5e22ed 100644 --- a/swarm.py +++ b/swarm.py @@ -1,6 +1,6 @@ import os -from run_utils import _bootstrap, _openswarm_state_root, _preload_agentswarm_bin +from run_utils import _openswarm_state_root _RUNTIME_CONFIGURED = False @@ -35,13 +35,6 @@ def _configure_runtime() -> None: _RUNTIME_CONFIGURED = True -if __name__ == "__main__": - _preload_agentswarm_bin() - _bootstrap() - -_configure_runtime() - - def create_agency(load_threads_callback=None): _configure_runtime() @@ -101,10 +94,8 @@ def create_agency(load_threads_callback=None): return agency -def _main() -> None: - agency = create_agency() - agency.tui(show_reasoning=True, reload=False) - - if __name__ == "__main__": - _main() + from run_utils import main as _run_main + _run_main() +else: + _configure_runtime() From a6527c53656600914db1f454d20b562cc0d47672 Mon Sep 17 00:00:00 2001 From: Nick Bobrowski <39348559+nicko-ai@users.noreply.github.com> Date: Sun, 31 May 2026 13:59:40 +0100 Subject: [PATCH 2/3] fix: support both OpenSwarm entry filenames - Set OpenSwarm product entry configuration to swarm.py,agency.py everywhere. - Keep swarm.py first for existing installs while allowing agency.py projects. - Extend launcher smoke coverage for the packaged npm profile. --- .github/workflows/build-tui.yml | 2 +- .github/workflows/live-run-mode-smoke.yml | 2 +- .github/workflows/test-mac.yml | 2 +- bin/openswarm | 2 +- run_utils.py | 2 +- scripts/smoke-bootstrap-onboard.py | 4 ++-- scripts/smoke-openswarm-launcher.js | 5 +++++ 7 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-tui.yml b/.github/workflows/build-tui.yml index 787583a3..f34e6b0f 100644 --- a/.github/workflows/build-tui.yml +++ b/.github/workflows/build-tui.yml @@ -201,7 +201,7 @@ jobs: AGENTSWARM_PRODUCT_MDNS_DOMAIN: openswarm.local AGENTSWARM_PRODUCT_STARTER_REPO: VRSEN/OpenSwarm AGENTSWARM_PRODUCT_STARTER_FOLDER: openswarm - AGENTSWARM_PRODUCT_ENTRY_FILES: swarm.py + AGENTSWARM_PRODUCT_ENTRY_FILES: swarm.py,agency.py AGENTSWARM_PRODUCT_SKIP_POST_AUTH_MODEL_SELECTION: "true" AGENTSWARM_PRODUCT_TUI_LOGO_LEFT: '[" "," ██████╗ ██████╗ ███████╗███╗ ██╗","██╔═══██╗██╔══██╗██╔════╝████╗ ██║","██║ ██║██████╔╝█████╗ ██╔██╗ ██║","██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║","╚██████╔╝██║ ███████╗██║ ╚████║"," ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝"]' AGENTSWARM_PRODUCT_TUI_LOGO_RIGHT: '["","███████╗██╗ ██╗ █████╗ ██████╗ ███╗ ███╗","██╔════╝██║ ██║██╔══██╗██╔══██╗████╗ ████║","███████╗██║ █╗ ██║███████║██████╔╝██╔████╔██║","╚════██║██║███╗██║██╔══██║██╔══██╗██║╚██╔╝██║","███████║╚███╔███╔╝██║ ██║██║ ██║██║ ╚═╝ ██║","╚══════╝ ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝"]' diff --git a/.github/workflows/live-run-mode-smoke.yml b/.github/workflows/live-run-mode-smoke.yml index 71e4d051..8da77536 100644 --- a/.github/workflows/live-run-mode-smoke.yml +++ b/.github/workflows/live-run-mode-smoke.yml @@ -55,7 +55,7 @@ jobs: AGENTSWARM_PRODUCT_MDNS_DOMAIN: openswarm.local AGENTSWARM_PRODUCT_STARTER_REPO: VRSEN/OpenSwarm AGENTSWARM_PRODUCT_STARTER_FOLDER: openswarm - AGENTSWARM_PRODUCT_ENTRY_FILES: swarm.py + AGENTSWARM_PRODUCT_ENTRY_FILES: swarm.py,agency.py AGENTSWARM_PRODUCT_SKIP_POST_AUTH_MODEL_SELECTION: "true" AGENTSWARM_PRODUCT_TUI_LOGO_LEFT: '[" "," ██████╗ ██████╗ ███████╗███╗ ██╗","██╔═══██╗██╔══██╗██╔════╝████╗ ██║","██║ ██║██████╔╝█████╗ ██╔██╗ ██║","██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║","╚██████╔╝██║ ███████╗██║ ╚████║"," ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝"]' AGENTSWARM_PRODUCT_TUI_LOGO_RIGHT: '["","███████╗██╗ ██╗ █████╗ ██████╗ ███╗ ███╗","██╔════╝██║ ██║██╔══██╗██╔══██╗████╗ ████║","███████╗██║ █╗ ██║███████║██████╔╝██╔████╔██║","╚════██║██║███╗██║██╔══██║██╔══██╗██║╚██╔╝██║","███████║╚███╔███╔╝██║ ██║██║ ██║██║ ╚═╝ ██║","╚══════╝ ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝"]' diff --git a/.github/workflows/test-mac.yml b/.github/workflows/test-mac.yml index 335f7983..5ab92c95 100644 --- a/.github/workflows/test-mac.yml +++ b/.github/workflows/test-mac.yml @@ -45,7 +45,7 @@ jobs: AGENTSWARM_PRODUCT_MDNS_DOMAIN: openswarm.local AGENTSWARM_PRODUCT_STARTER_REPO: VRSEN/OpenSwarm AGENTSWARM_PRODUCT_STARTER_FOLDER: openswarm - AGENTSWARM_PRODUCT_ENTRY_FILES: swarm.py + AGENTSWARM_PRODUCT_ENTRY_FILES: swarm.py,agency.py AGENTSWARM_PRODUCT_TUI_LOGO_LEFT: '[" "," ██████╗ ██████╗ ███████╗███╗ ██╗","██╔═══██╗██╔══██╗██╔════╝████╗ ██║","██║ ██║██████╔╝█████╗ ██╔██╗ ██║","██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║","╚██████╔╝██║ ███████╗██║ ╚████║"," ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝"]' AGENTSWARM_PRODUCT_TUI_LOGO_RIGHT: '["","███████╗██╗ ██╗ █████╗ ██████╗ ███╗ ███╗","██╔════╝██║ ██║██╔══██╗██╔══██╗████╗ ████║","███████╗██║ █╗ ██║███████║██████╔╝██╔████╔██║","╚════██║██║███╗██║██╔══██║██╔══██╗██║╚██╔╝██║","███████║╚███╔███╔╝██║ ██║██║ ██║██║ ╚═╝ ██║","╚══════╝ ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝"]' AGENTSWARM_PRODUCT_WORDMARK_LINES: '[""," ██████╗ ██████╗ ███████╗███╗ ██╗ ███████╗██╗ ██╗ █████╗ ██████╗ ███╗ ███╗","██╔═══██╗██╔══██╗██╔════╝████╗ ██║ ██╔════╝██║ ██║██╔══██╗██╔══██╗████╗ ████║","██║ ██║██████╔╝█████╗ ██╔██╗ ██║ ███████╗██║ █╗ ██║███████║██████╔╝██╔████╔██║","██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║ ╚════██║██║███╗██║██╔══██╗██╔══██╗██║╚██╔╝██║","╚██████╔╝██║ ███████╗██║ ╚████║ ███████║╚███╔███╔╝██║ ██║██║ ██║██║ ╚═╝ ██║"," ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚══════╝ ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝"]' diff --git a/bin/openswarm b/bin/openswarm index 747f3596..532d0502 100755 --- a/bin/openswarm +++ b/bin/openswarm @@ -60,7 +60,7 @@ const downstreamEnv = { AGENTSWARM_PRODUCT_MDNS_DOMAIN: 'openswarm.local', AGENTSWARM_PRODUCT_STARTER_REPO: 'VRSEN/OpenSwarm', AGENTSWARM_PRODUCT_STARTER_FOLDER: 'openswarm', - AGENTSWARM_PRODUCT_ENTRY_FILES: 'swarm.py', + AGENTSWARM_PRODUCT_ENTRY_FILES: 'swarm.py,agency.py', AGENTSWARM_PRODUCT_SKIP_POST_AUTH_MODEL_SELECTION: 'true', AGENTSWARM_PRODUCT_TUI_LOGO_LEFT: JSON.stringify(productTuiLogoLeft), AGENTSWARM_PRODUCT_TUI_LOGO_RIGHT: JSON.stringify(productTuiLogoRight), diff --git a/run_utils.py b/run_utils.py index 1593142e..e66824fb 100644 --- a/run_utils.py +++ b/run_utils.py @@ -60,7 +60,7 @@ def _load_openswarm_dotenv(*, override: bool = False) -> bool: def _configure_product_env() -> None: os.environ.setdefault("AGENTSWARM_PRODUCT_SKIP_POST_AUTH_MODEL_SELECTION", "true") - os.environ.setdefault("AGENTSWARM_PRODUCT_ENTRY_FILES", "swarm.py") + os.environ.setdefault("AGENTSWARM_PRODUCT_ENTRY_FILES", "swarm.py,agency.py") os.environ.setdefault("AGENTSWARM_PRODUCT_TUI_LOGO_LEFT", _PRODUCT_TUI_LOGO_LEFT) os.environ.setdefault("AGENTSWARM_PRODUCT_TUI_LOGO_RIGHT", _PRODUCT_TUI_LOGO_RIGHT) os.environ.setdefault("AGENTSWARM_PRODUCT_WORDMARK_LINES", _PRODUCT_WORDMARK_LINES) diff --git a/scripts/smoke-bootstrap-onboard.py b/scripts/smoke-bootstrap-onboard.py index 9ec3523e..644de426 100644 --- a/scripts/smoke-bootstrap-onboard.py +++ b/scripts/smoke-bootstrap-onboard.py @@ -208,8 +208,8 @@ def smoke_product_state_root_env() -> None: if os.environ.get("AGENTSWARM_PRODUCT_STATE_ROOT") != str(root): raise RuntimeError("OpenSwarm did not configure AGENTSWARM_PRODUCT_STATE_ROOT from OPENSWARM_STATE_ROOT") - if os.environ.get("AGENTSWARM_PRODUCT_ENTRY_FILES") != "swarm.py": - raise RuntimeError("OpenSwarm Python path did not configure swarm.py as the product entry file") + if os.environ.get("AGENTSWARM_PRODUCT_ENTRY_FILES") != "swarm.py,agency.py": + raise RuntimeError("OpenSwarm Python path did not configure the expected product entry files") if os.environ.get("OPENAI_API_KEY") != "state-openai": raise RuntimeError("OpenSwarm did not load dotenv values from the fixed state root before caller cwd") if os.environ.get("AGENTSWARM_BIN") != "/explicit/bin": diff --git a/scripts/smoke-openswarm-launcher.js b/scripts/smoke-openswarm-launcher.js index 684c1e8b..77231cce 100644 --- a/scripts/smoke-openswarm-launcher.js +++ b/scripts/smoke-openswarm-launcher.js @@ -132,6 +132,10 @@ function assertProductAddons(api) { ]) } +function assertProductEntryFiles(api) { + assert.equal(api.downstreamEnv.AGENTSWARM_PRODUCT_ENTRY_FILES, 'swarm.py,agency.py') +} + function assertStateRoot() { const linux = load({ platform: 'linux', @@ -178,6 +182,7 @@ async function main() { assert.equal(musl.api.shouldUseDependencyBinary(), true) assert.equal(await musl.api.ensureCustomBinary(), null) assert.deepEqual(musl.requests, []) + assertProductEntryFiles(musl.api) assertProductAddons(musl.api) assertStateRoot() From 81efa15cca539272d207ccee687daac79065787f Mon Sep 17 00:00:00 2001 From: Nick Bobrowski <39348559+nicko-ai@users.noreply.github.com> Date: Sun, 31 May 2026 14:20:38 +0100 Subject: [PATCH 3/3] test: align OpenSwarm smoke workspace - remove the competing root agency.py fixture from the OpenSwarm roster smoke - keep the smoke focused on the packaged OpenSwarm starter after agency.py becomes a supported entry name --- scripts/smoke-run-mode.py | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/scripts/smoke-run-mode.py b/scripts/smoke-run-mode.py index ecbb28fa..bb0370e0 100644 --- a/scripts/smoke-run-mode.py +++ b/scripts/smoke-run-mode.py @@ -494,22 +494,10 @@ def main() -> int: package_dir = root / "node_modules" / "@vrsen" / "openswarm" if openswarm_tui_binary: install_openswarm_tui_binary(package_dir, openswarm_tui_binary) - generic_dir = root / "my-agency" - generic_dir.mkdir() - (generic_dir / "agency.py").write_text( - "\n".join( - [ - "from agency_swarm import Agency", - "", - "def create_agency(load_threads_callback=None):", - " return Agency(name='Generic Agency')", - "", - ] - ), - encoding="utf-8", - ) - create_local_openswarm_project(package_dir, generic_dir) - plain = run_tui_smoke(launcher, package_dir, generic_dir, root, env, args.check, args.prompt, args.expect, args.timeout) + workspace = root / "workspace" + workspace.mkdir() + create_local_openswarm_project(package_dir, workspace) + plain = run_tui_smoke(launcher, package_dir, workspace, root, env, args.check, args.prompt, args.expect, args.timeout) if "Agency Swarm Default" not in plain: raise RuntimeError("Smoke response was seen, but Agency Swarm Run mode was not detected") if args.check in {"agents", "all"}: