Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@ build
dist
results
eval_results
Dockerfile
docker-compose.yml
.pytest_cache
34 changes: 34 additions & 0 deletions Dockerfile.api
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
FROM python:3.12-slim AS builder

ENV PYTHONDONTWRITEBYTECODE=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1

RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

WORKDIR /build
COPY . .
RUN pip install --no-cache-dir ".[api]"

FROM python:3.12-slim

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1

COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

RUN useradd --create-home appuser \
&& install -d -m 0755 -o appuser -g appuser /home/appuser/.tradingagents
USER appuser
WORKDIR /home/appuser/app

COPY --from=builder --chown=appuser:appuser /build .

EXPOSE 8000

HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" || exit 1

ENTRYPOINT []
CMD ["python", "run_server.py", "--host", "0.0.0.0", "--port", "8000"]
15 changes: 14 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
services:
tradingagents:
build: .
build:
context: .
dockerfile: Dockerfile
env_file:
- .env
volumes:
- tradingagents_data:/home/appuser/.tradingagents
tty: true
stdin_open: true

tradingagents-api:
build:
context: .
dockerfile: Dockerfile.api
env_file:
- .env
ports:
- "8000:8000"
volumes:
- tradingagents_data:/home/appuser/.tradingagents

ollama:
image: ollama/ollama:latest
volumes:
Expand Down
8 changes: 8 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,15 @@ dependencies = [

[project.optional-dependencies]
dev = [
"invoke>=2.2",
"ruff>=0.15",
"pytest>=8.0",
"pytest-subtests>=0.13",
"pytest-asyncio>=0.24.0",
]
api = [
"fastapi>=0.115.0",
"uvicorn[standard]>=0.34.0",
]
# Amazon Bedrock support (AWS SigV4 auth + boto3). Optional so the core install
# stays lean: pip install "tradingagents[bedrock]".
Expand All @@ -61,10 +67,12 @@ markers = [
"unit: fast isolated unit tests",
"integration: tests requiring external services",
"smoke: quick sanity-check tests",
"asyncio: async tests with pytest-asyncio",
]
filterwarnings = [
"ignore::DeprecationWarning",
]
asyncio_mode = "auto"

[tool.ruff]
line-length = 100
Expand Down
108 changes: 108 additions & 0 deletions run_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/usr/bin/env python
"""Entry point script to run the TradingAgents API server.

Usage:
python run_server.py # Default: localhost:8000
python run_server.py --host 0.0.0.0 # Bind to all interfaces
python run_server.py --port 8080 # Custom port
python run_server.py --reload # Enable auto-reload for development

Or use uvicorn directly:
uvicorn tradingagents.api:create_app --factory --host 0.0.0.0 --port 8000
"""

from __future__ import annotations

import argparse
import sys
import os

# Add project root to path if run as script
project_root = os.path.dirname(os.path.abspath(__file__))
if project_root not in sys.path:
sys.path.insert(0, project_root)


def main():
"""Parse arguments and start the server."""
parser = argparse.ArgumentParser(
description="Run the TradingAgents API server",
)
parser.add_argument(
"--host",
default="0.0.0.0",
help="Host to bind the server to (default: 0.0.0.0)",
)
parser.add_argument(
"--port",
type=int,
default=8000,
help="Port to bind the server to (default: 8000)",
)
parser.add_argument(
"--reload",
action="store_true",
help="Enable auto-reload for development",
)
parser.add_argument(
"--workers",
type=int,
default=1,
help="Number of worker processes (default: 1)",
)
parser.add_argument(
"--log-level",
default="info",
choices=["debug", "info", "warning", "error", "critical"],
help="Logging level (default: info)",
)

args = parser.parse_args()

try:
import uvicorn
except ImportError:
print(
"Error: uvicorn is not installed. "
"Install it with: pip install uvicorn[standard] "
"or: pip install -e '.[api]'",
file=sys.stderr,
)
sys.exit(1)

try:
from tradingagents.api import create_app
except ImportError as e:
print(
f"Error: Failed to import tradingagents.api: {e}",
file=sys.stderr,
)
sys.exit(1)

if args.workers > 1 and not args.reload:
print(
f"Warning: --workers {args.workers} is not supported by the task API.\n"
" Task state lives in process memory, so a task created in one worker\n"
" returns 404 when the status poll lands on another, and the effective\n"
" concurrency becomes task_max_concurrent x workers.\n"
" Raise TRADINGAGENTS_TASK_MAX_CONCURRENT instead of adding workers.",
file=sys.stderr,
)

print(f"Starting TradingAgents API server on {args.host}:{args.port}")
print(f"API docs: http://{args.host}:{args.port}/api/v1/docs")
print(f"Health check: http://{args.host}:{args.port}/health")

uvicorn.run(
"tradingagents.api:create_app",
factory=True,
host=args.host,
port=args.port,
reload=args.reload,
workers=1 if args.reload else args.workers, # reload only supports 1 worker
log_level=args.log_level,
)


if __name__ == "__main__":
main()
Loading