migrate: switch to uv from poetry

This commit is contained in:
sharath 2025-06-15 12:29:47 +00:00
parent f72440d652
commit 64b4be39fe
No known key found for this signature in database
15 changed files with 2280 additions and 4187 deletions

133
backend/.dockerignore Normal file
View File

@ -0,0 +1,133 @@
# Version control
.git
.gitignore
.gitattributes
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# Virtual environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# IDE and editors
.vscode/
.idea/
*.swp
*.swo
*~
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Logs
*.log
logs/
# Test coverage
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Documentation
docs/
*.md
README*
# CI/CD
.github/
.gitlab-ci.yml
.travis.yml
.circleci/
# Docker
Dockerfile*
docker-compose*.yml
.dockerignore
# Development tools
.mypy_cache/
.dmypy.json
dmypy.json
.pyre/
.pytype/
cython_debug/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# Environment variables (keep .env files out for security)
.env*
!.env.example
# Temporary files
*.tmp
*.temp
.tmp/
.temp/
# Node.js (if any frontend assets)
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Database
*.db
*.sqlite3
# Certificates and keys
*.pem
*.key
*.crt
*.cert
# Local development files
.local/
.cache/

View File

@ -1,56 +0,0 @@
name: Bump Version
on:
workflow_dispatch:
inputs:
version_part:
description: 'Part of version to bump (major, minor, patch)'
required: true
default: 'patch'
type: choice
options:
- major
- minor
- patch
# Add these permissions
permissions:
contents: write
pull-requests: write
jobs:
bump-version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'
- name: Install Poetry
run: |
curl -sSL https://install.python-poetry.org | python3 -
- name: Configure Git
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
- name: Bump version
run: |
poetry version ${{ github.event.inputs.version_part }}
NEW_VERSION=$(poetry version -s)
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5
with:
commit-message: "chore: bump version to ${{ env.NEW_VERSION }}"
title: "Bump version to ${{ env.NEW_VERSION }}"
body: "Automated version bump to ${{ env.NEW_VERSION }}"
branch: "bump-version-${{ env.NEW_VERSION }}"
base: "main"

View File

@ -1,27 +0,0 @@
name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'
- name: Install Poetry
run: |
curl -sSL https://install.python-poetry.org | python3 -
- name: Update lock file and install dependencies
run: |
poetry lock
poetry install

View File

@ -1,33 +0,0 @@
name: Publish to PyPI
on:
release:
types: [published]
# Allows manual trigger from GitHub Actions tab
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'
- name: Install Poetry
run: |
curl -sSL https://install.python-poetry.org | python3 -
- name: Configure Poetry
run: |
poetry config pypi-token.pypi ${{ secrets.PYPI_TOKEN }}
- name: Build package
run: poetry build
- name: Publish to PyPI
run: poetry publish

View File

@ -1,63 +1,54 @@
FROM python:3.11-slim
# Set environment variables
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
ENV_MODE="production" \
PYTHONPATH=/app
FROM ubuntu:24.04
ENV ENV_MODE production
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
curl \
&& rm -rf /var/lib/apt/lists/*
# Create non-root user and set up directories
RUN useradd -m -u 1000 appuser && \
mkdir -p /app/logs && \
chown -R appuser:appuser /app
build-essential \
curl \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies
COPY --chown=appuser:appuser requirements.txt .
COPY --chown=appuser:appuser pyproject.toml uv.lock ./
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
RUN uv pip install --system --no-cache-dir -r requirements.txt gunicorn
# Switch to non-root user
USER appuser
ENV UV_LINK_MODE=copy
ENV UV_PYTHON_PREFERENCE=system
# RUN --mount=type=cache,target=/root/.cache/uv uv sync --locked --compile-bytecode --no-editable
RUN uv venv --system-site-packages
RUN --mount=type=cache,target=/root/.cache/uv uv sync --locked --quiet
ENV PATH="/app/.venv/bin:$PATH"
# Copy application code
COPY --chown=appuser:appuser . .
# Expose the port the app runs on
EXPOSE 8000
COPY . .
RUN uv run python --version
# Calculate optimal worker count based on 16 vCPUs
# Using (2*CPU)+1 formula for CPU-bound applications
ENV WORKERS=33
ENV THREADS=2
ENV WORKERS=1
ENV THREADS=1
ENV WORKER_CONNECTIONS=2000
EXPOSE 8000
# Gunicorn configuration
CMD ["sh", "-c", "gunicorn api:app \
--workers $WORKERS \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:8000 \
--timeout 1800 \
--graceful-timeout 600 \
--keep-alive 1800 \
--max-requests 0 \
--max-requests-jitter 0 \
--forwarded-allow-ips '*' \
--worker-connections $WORKER_CONNECTIONS \
--worker-tmp-dir /dev/shm \
--preload \
--log-level info \
--access-logfile - \
--error-logfile - \
--capture-output \
--enable-stdio-inheritance \
--threads $THREADS"]
CMD ["sh", "-c", "uv run gunicorn api:app \
--workers $WORKERS \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:8000 \
--timeout 1800 \
--graceful-timeout 600 \
--keep-alive 1800 \
--max-requests 0 \
--max-requests-jitter 0 \
--forwarded-allow-ips '*' \
--worker-connections $WORKER_CONNECTIONS \
--worker-tmp-dir /dev/shm \
--preload \
--log-level info \
--access-logfile - \
--error-logfile - \
--capture-output \
--enable-stdio-inheritance \
--threads $THREADS"]

View File

@ -40,11 +40,11 @@ Then you can run your API service locally with the following commands
```sh
# On one terminal
cd backend
poetry run python3.11 api.py
uv run python api.py
# On another terminal
cd frontend
poetry run python3.11 -m dramatiq run_agent_background
uv run python -m dramatiq run_agent_background
```
### Environment Configuration

View File

@ -10,7 +10,7 @@ services:
memory: 32G
worker:
command: python -m dramatiq --processes 40 --threads 8 run_agent_background
command: uvx dramatiq --processes 40 --threads 8 run_agent_background
deploy:
resources:
limits:

View File

@ -42,7 +42,8 @@ services:
build:
context: .
dockerfile: Dockerfile
command: python -m dramatiq --processes 4 --threads 4 run_agent_background
command: sleep infinity
# command: dramatiq --processes 4 --threads 4 run_agent_background
env_file:
- .env
volumes:

4
backend/docker/entrypoint.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
source .venv/bin/activate
exec "$@"

3907
backend/poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,75 +1,73 @@
[tool.poetry]
[project]
name = "suna"
version = "1.0"
description = "open source generalist AI Agent"
authors = ["marko-kraemer <mail@markokraemer.com>"]
authors = [{ name = "marko-kraemer", email = "mail@markokraemer.com" }]
readme = "README.md"
license = "MIT"
homepage = "https://www.suna.so/"
repository = "https://github.com/kortix-ai/suna"
license = { text = "Apache-2.0" }
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Libraries :: Python Modules",
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache-2.0 License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Libraries :: Python Modules",
]
requires-python = "==3.11.10"
dependencies = [
"python-dotenv==1.0.1",
"litellm==1.66.1",
"click==8.1.7",
"questionary==2.0.1",
"requests==2.32.3",
"packaging==24.1",
"setuptools==75.3.0",
"pytest==8.3.3",
"pytest-asyncio==0.24.0",
"asyncio==3.4.3",
"altair==4.2.2",
"prisma==0.15.0",
"fastapi==0.115.12",
"uvicorn==0.27.1",
"python-multipart==0.0.20",
"redis==5.2.1",
"upstash-redis==1.3.0",
"supabase==2.15.0",
"pyjwt==2.10.1",
"exa-py==1.9.1",
"e2b-code-interpreter==1.2.0",
"certifi==2024.2.2",
"python-ripgrep==0.0.6",
"daytona-sdk==0.21.0a4",
"daytona-api-client==0.21.0a1",
"daytona-api-client-async==0.21.0a1",
"boto3==1.37.3",
"openai==1.72.0",
"nest-asyncio==1.6.0",
"vncdotool==1.2.0",
"tavily-python==0.5.4",
"pytesseract==0.3.13",
"stripe==12.0.1",
"dramatiq==1.17.1",
"pika==1.3.2",
"prometheus-client==0.21.1",
"langfuse==2.60.5",
"Pillow==10.0.0",
"mcp==1.0.0",
"httpx==0.28.0",
"aiohttp==3.12.0",
"email-validator==2.0.0",
"mailtrap==2.0.1",
"sentry-sdk[fastapi]==2.29.1",
"gunicorn>=23.0.0",
]
[tool.poetry.dependencies]
python = "^3.11"
python-dotenv = "1.0.1"
litellm = "1.66.1"
click = "8.1.7"
questionary = "2.0.1"
requests = "^2.31.0"
packaging = "24.1"
setuptools = "75.3.0"
pytest = "8.3.3"
pytest-asyncio = "0.24.0"
asyncio = "3.4.3"
altair = "4.2.2"
prisma = "0.15.0"
fastapi = "0.110.0"
uvicorn = "0.27.1"
python-multipart = "0.0.20"
redis = "5.2.1"
upstash-redis = "1.3.0"
supabase = "^2.15.0"
pyjwt = "2.10.1"
exa-py = "^1.9.1"
e2b-code-interpreter = "^1.2.0"
certifi = "2024.2.2"
python-ripgrep = "0.0.6"
daytona_sdk = "^0.20.2"
boto3 = "^1.34.0"
openai = "^1.72.0"
nest-asyncio = "^1.6.0"
vncdotool = "^1.2.0"
tavily-python = "^0.5.4"
pytesseract = "^0.3.13"
stripe = "^12.0.1"
dramatiq = "^1.17.1"
pika = "^1.3.2"
prometheus-client = "^0.21.1"
langfuse = "^2.60.5"
Pillow = "^10.0.0"
mcp = "^1.0.0"
sentry-sdk = {extras = ["fastapi"], version = "^2.29.1"}
httpx = "^0.28.0"
aiohttp = "^3.9.0"
email-validator = "^2.0.0"
mailtrap = "^2.0.1"
[project.urls]
homepage = "https://www.suna.so/"
repository = "https://github.com/kortix-ai/suna"
[tool.poetry.scripts]
[project.scripts]
agentpress = "agentpress.cli:main"
[[tool.poetry.packages]]
include = "agentpress"
[tool.poetry.group.dev.dependencies]
daytona-sdk = "^0.20.2"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.uv]
package = false

View File

@ -1,43 +0,0 @@
python-dotenv==1.0.1
litellm==1.66.1
click==8.1.7
questionary==2.0.1
requests>=2.31.0
packaging==24.1
setuptools==75.3.0
pytest==8.3.3
pytest-asyncio==0.24.0
asyncio==3.4.3
altair==4.2.2
prisma==0.15.0
fastapi==0.110.0
uvicorn==0.27.1
python-multipart==0.0.20
redis==5.2.1
upstash-redis==1.3.0
supabase>=2.15.0
pyjwt==2.10.1
exa-py>=1.9.1
e2b-code-interpreter>=1.2.0
certifi==2024.2.2
python-ripgrep==0.0.6
daytona-sdk==0.20.2
boto3>=1.34.0
openai>=1.72.0
nest-asyncio>=1.6.0
vncdotool>=1.2.0
tavily-python>=0.5.4
pytesseract==0.3.13
stripe>=12.0.1
dramatiq>=1.17.1
pika>=1.3.2
prometheus-client>=0.21.1
langfuse==2.60.5
httpx>=0.24.0
Pillow>=10.0.0
sentry-sdk[fastapi]>=2.29.1
mcp>=1.0.0
mcp_use>=1.0.0
aiohttp>=3.9.0
email-validator>=2.0.0
mailtrap>=2.0.1

2024
backend/uv.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@ -63,12 +63,15 @@ Obtain the following API keys:
Ensure the following tools are installed on your system:
- **[Git](https://git-scm.com/downloads)**
- **[Docker](https://docs.docker.com/get-docker/)**
- **[Python 3.11](https://www.python.org/downloads/)**
- **[Poetry](https://python-poetry.org/docs/#installation)**
- **[Node.js & npm](https://nodejs.org/en/download/)**
- **[Supabase CLI](https://supabase.com/docs/guides/local-development/cli/getting-started)**
- **[Git](https://git-scm.com/downloads)**
- **[Python 3.11](https://www.python.org/downloads/)**
For manual setup, you'll also need:
- **[uv](https://docs.astral.sh/uv/)**
- **[Node.js & npm](https://nodejs.org/en/download/)**
## Installation Steps
@ -212,6 +215,8 @@ This method requires you to start each component separately:
```bash
docker compose up redis rabbitmq -d
# or
python start.py # Use the same to stop it later
```
2. Start the frontend (in one terminal):
@ -225,14 +230,14 @@ npm run dev
```bash
cd backend
poetry run python3.11 api.py
uv run python api.py
```
4. Start the worker (in one more terminal):
```bash
cd backend
poetry run python3.11 -m dramatiq run_agent_background
uv run python -m dramatiq run_agent_background
```
## Troubleshooting
@ -273,11 +278,11 @@ npm run dev
# Backend logs (manual setup)
cd backend
poetry run python3.11 api.py
uv run python api.py
# Worker logs (manual setup)
cd backend
poetry run python3.11 -m dramatiq run_agent_background
uv run python -m dramatiq run_agent_background
```
---

View File

@ -2,3 +2,6 @@
[tools]
node = "20"
python = "3.11.10"
[env]
_.python.venv = { path = "backend/.venv", create = true }