diff --git a/.env.example b/.env.example index 30cc10b..c3bb256 100644 --- a/.env.example +++ b/.env.example @@ -4,7 +4,12 @@ LLM_API_KEY=sk-or-v1-xxx LLM_MODEL=anthropic/claude-3.5-sonnet LLM_API_BASE= -# Auth (CHANGE THIS!) +# MCP Tool Server — URL MUST include the /mcp path (FastMCP HTTP transport). +# Example: http://mcp-tools:8501/mcp (the docker-compose default already includes /mcp) +MCP_SERVER_URL=http://mcp-tools:8501/mcp + +# Auth (CHANGE THIS — must be >=32 chars, must NOT be the default below) +# Generate one with: python -c "import secrets;print(secrets.token_urlsafe(32))" AUTH_TOKEN=change-me-to-something-secure # Logging diff --git a/agent_platform/Dockerfile b/agent_platform/Dockerfile index afbf4ff..4a4c7ef 100644 --- a/agent_platform/Dockerfile +++ b/agent_platform/Dockerfile @@ -13,7 +13,8 @@ RUN pip install --no-cache-dir --upgrade pip && \ COPY . . RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app -USER appuser +# B4: run as root for staging so /data volume is writable without chown entrypoint. +# (Bind-mounted /data from host typically has host UID, not 1000.) EXPOSE 8000 diff --git a/agent_platform/agent.py b/agent_platform/agent.py index ab2d1d2..40276da 100644 --- a/agent_platform/agent.py +++ b/agent_platform/agent.py @@ -76,13 +76,15 @@ async def run_agent_turn( if not agent["enabled"]: raise ValueError(f"Agent '{agent_id}' ist deaktiviert") + # History laden (letzte 20 Messages) — VOR dem Speichern der neuen User-Message, + # damit die neue Turn-User-Message nicht versehentlich aus dem Slice fällt. + history = await get_messages(db, conversation_id, limit=20) + # User-Message speichern await add_message(db, conversation_id, "user", user_message) - # History laden (letzte 20 Messages) - history = await get_messages(db, conversation_id, limit=20) messages: List[dict] = [{"role": "system", "content": agent["system_prompt"]}] - for row in history[:-1]: # ohne die gerade gespeicherte user-Message + for row in history: role, content, tool_calls_json, _, _ = row if role == "tool": continue @@ -94,6 +96,9 @@ async def run_agent_turn( pass messages.append(msg) + # Aktuelle User-Message explizit anhängen, damit das LLM den neuen Turn sieht. + messages.append({"role": "user", "content": user_message}) + # MCP-Tools laden (gefiltert nach allowed_tools) mcp_client = get_mcp_client() tools = [] diff --git a/agent_platform/api.py b/agent_platform/api.py index 59dc6ad..555ccaf 100644 --- a/agent_platform/api.py +++ b/agent_platform/api.py @@ -60,13 +60,19 @@ class AgentUpdate(BaseModel): class ChatMessage(BaseModel): - message: str = Field(..., min_length=1) + message: str = Field(..., min_length=1, max_length=32000) # === App === @asynccontextmanager async def lifespan(app: FastAPI): + # B1 Boot Guard: refuse to start with default or weak AUTH_TOKEN + if settings.AUTH_TOKEN == "change-me-in-production" or len(settings.AUTH_TOKEN) < 32: + raise RuntimeError( + "AUTH_TOKEN env var is unset or weak (must be >=32 chars and not the default " + "'change-me-in-production'). Set a strong AUTH_TOKEN before starting the service." + ) Path(settings.DB_PATH).parent.mkdir(parents=True, exist_ok=True) db = await aiosqlite.connect(settings.DB_PATH) try: diff --git a/agent_platform/audit.py b/agent_platform/audit.py index e5554aa..35b2383 100644 --- a/agent_platform/audit.py +++ b/agent_platform/audit.py @@ -6,7 +6,7 @@ from typing import Optional, Dict, Any import aiosqlite from config import settings -from db import log_audit, get_db +from db import log_audit logger = logging.getLogger("audit") diff --git a/docker-compose.yml b/docker-compose.yml index 04d03b6..d6d1141 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,14 +11,21 @@ services: - LLM_API_KEY=${LLM_API_KEY} - LLM_MODEL=${LLM_MODEL:-anthropic/claude-3.5-sonnet} - LLM_API_BASE=${LLM_API_BASE:-} - - MCP_SERVER_URL=http://mcp-tools:8501 + - MCP_SERVER_URL=http://mcp-tools:8501/mcp - AUTH_TOKEN=${AUTH_TOKEN} - DB_PATH=/data/agent-platform.db - LOG_LEVEL=${LOG_LEVEL:-info} volumes: - agent-data:/data depends_on: - - mcp-tools + mcp-tools: + condition: service_healthy + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/health"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s restart: unless-stopped networks: - agent-net @@ -36,6 +43,12 @@ services: environment: - MCP_HOST=0.0.0.0 - MCP_PORT=8501 + healthcheck: + test: ["CMD-SHELL", "(echo > /dev/tcp/127.0.0.1/8501) >/dev/null 2>&1 || exit 1"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s restart: unless-stopped networks: - agent-net