mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-17 18:25:42 +02:00
91 lines
3.5 KiB
Bash
Executable File
91 lines
3.5 KiB
Bash
Executable File
#!/bin/bash
|
|
# The comment above is shebang, DO NOT REMOVE
|
|
DEV_ABSPATH="$(readlink -f "${BASH_SOURCE[0]}")"
|
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
# echo "In macOS server sed START"
|
|
# echo "SERVER_ABSPATH: $SERVER_ABSPATH"
|
|
sed -i '' 's/\r//g' "$DEV_ABSPATH"
|
|
# echo "In macOS server sed END"
|
|
else
|
|
# echo "NOT in macOS server START"
|
|
# echo "SERVER_ABSPATH: $SERVER_ABSPATH"
|
|
sed -i 's/\r//g' "$DEV_ABSPATH"
|
|
# echo "NOT in macOS server START"
|
|
fi
|
|
chmod +x "$DEV_ABSPATH"
|
|
|
|
PROJECT_ROOT_ABSPATH="$(dirname "$(dirname "$DEV_ABSPATH")")"
|
|
BACKEND_DIR_ABSPATH="$PROJECT_ROOT_ABSPATH/backend"
|
|
|
|
# Cleanup function on exit
|
|
cleanup() {
|
|
echo "Shutting down..."
|
|
cd - > /dev/null 2>&1
|
|
}
|
|
trap cleanup EXIT INT TERM
|
|
|
|
# --- Create virtual environment if it doesn't exist ---
|
|
VENV_DIR="$BACKEND_DIR_ABSPATH/.venv"
|
|
if [[ ! -d "$VENV_DIR" ]]; then
|
|
echo "Creating virtual environment..."
|
|
python3 -m venv "$VENV_DIR"
|
|
fi
|
|
source "$VENV_DIR/bin/activate"
|
|
|
|
# --- Install Python dependencies ---
|
|
echo "Installing dependencies..."
|
|
cd "$BACKEND_DIR_ABSPATH"
|
|
pip3 install -r requirements.txt
|
|
if [[ $? -ne 0 ]]; then
|
|
echo "Failed to install Python dependencies."
|
|
exit 1
|
|
fi
|
|
|
|
# --- Start the backend server ---
|
|
# IMPORTANT: --reload-exclude must cover every path the running backend
|
|
# itself may WRITE to. Without this, the App Builder agent writing into
|
|
# a workspace's backend (e.g. backend/data/outputs_workspace/<ws>/backend/
|
|
# apps/chat/chat.py) triggers WatchFiles, which reloads uvicorn,
|
|
# which closes the agent's WebSocket mid-stream — visible to the user
|
|
# as the agent randomly "stopping" and needing a Resume.
|
|
#
|
|
# Caveat about uvicorn's pattern semantics: glob strings like `*/data/*`
|
|
# get matched via `Path.match`, which is RIGHT-anchored and doesn't
|
|
# match deep paths. Only `--reload-exclude` values that resolve to a
|
|
# real directory at config time get added to uvicorn's dir-exclude list
|
|
# (compared via `dir in path.parents`). So we pass ABSOLUTE paths to
|
|
# the dirs we want to exclude — those are the only patterns uvicorn's
|
|
# WatchFilesReload actually honors for "anywhere under this tree".
|
|
# Dev only: OPENSWARM_PORT lets a parallel worktree bind its own backend port instead of colliding on 8324. Packaged builds never set it.
|
|
BACKEND_PORT="${OPENSWARM_PORT:-8324}"
|
|
echo "Starting backend server on http://0.0.0.0:${BACKEND_PORT} ..."
|
|
cd "$PROJECT_ROOT_ABSPATH"
|
|
|
|
UVICORN_EXCLUDE_ARGS=(--reload-exclude '*.pyc')
|
|
for d in \
|
|
"$BACKEND_DIR_ABSPATH/data" \
|
|
"$BACKEND_DIR_ABSPATH/mcp-bundles" \
|
|
"$BACKEND_DIR_ABSPATH/apps/outputs/webapp_template" \
|
|
; do
|
|
if [[ -d "$d" ]]; then
|
|
UVICORN_EXCLUDE_ARGS+=(--reload-exclude "$d")
|
|
fi
|
|
done
|
|
|
|
# --reload is purely a dev-loop convenience — auto-restart on source
|
|
# edits. Useless for end users running the packaged DMG (no source to
|
|
# edit) and actively harmful: WatchFiles uses real fs handles, the
|
|
# reload supervisor adds a couple hundred MB of resident memory, and
|
|
# every reload tears down running agent WebSockets. Only enable it
|
|
# when the top-level run.sh has set OPENSWARM_DEV=1 (which the dev
|
|
# launcher does). Packaged builds leave it unset → fast, lean,
|
|
# single-process uvicorn.
|
|
if [[ "${OPENSWARM_DEV:-}" == "1" ]]; then
|
|
echo "OPENSWARM_DEV=1 detected, running uvicorn with --reload."
|
|
python3 -m uvicorn backend.main:app --host 0.0.0.0 --port "$BACKEND_PORT" --reload \
|
|
--reload-dir "$BACKEND_DIR_ABSPATH" \
|
|
"${UVICORN_EXCLUDE_ARGS[@]}"
|
|
else
|
|
python3 -m uvicorn backend.main:app --host 0.0.0.0 --port "$BACKEND_PORT"
|
|
fi
|