diff --git a/backend/entrypoint.sh b/backend/entrypoint.sh index a38723a9d..4caceac3c 100755 --- a/backend/entrypoint.sh +++ b/backend/entrypoint.sh @@ -16,8 +16,17 @@ role_contains() { # --- Permission fixing and privilege dropping --- if [ "$(id -u)" = '0' ]; then - echo "[entrypoint] Detected root user, fixing permissions..." - chown -R clawith:clawith ${AGENT_DATA_DIR} + echo "[entrypoint] Detected root user, checking permissions..." + TARGET_DIR="${AGENT_DATA_DIR:-/data/agents}" + if [ -d "${TARGET_DIR}" ]; then + CURRENT_OWNER=$(stat -c '%U:%G' "${TARGET_DIR}" 2>/dev/null || echo "") + if [ "${CURRENT_OWNER}" != "clawith:clawith" ]; then + echo "[entrypoint] Directory ${TARGET_DIR} owner is '${CURRENT_OWNER}', fixing permissions..." + chown -R clawith:clawith "${TARGET_DIR}" + else + echo "[entrypoint] Directory ${TARGET_DIR} is already owned by clawith:clawith, skipping chown." + fi + fi echo "[entrypoint] Dropping privileges to 'clawith' and re-executing..." exec gosu clawith /bin/bash "$0" "$@" diff --git a/deploy/docker-compose-multi.yml b/deploy/docker-compose-multi.yml index 3c5c7ea21..d0f09ac10 100644 --- a/deploy/docker-compose-multi.yml +++ b/deploy/docker-compose-multi.yml @@ -48,7 +48,7 @@ services: backend-api: build: - context: ./backend + context: ../backend args: CLAWITH_PIP_INDEX_URL: ${CLAWITH_PIP_INDEX_URL:-} CLAWITH_PIP_TRUSTED_HOST: ${CLAWITH_PIP_TRUSTED_HOST:-} @@ -79,10 +79,10 @@ services: PUBLIC_BASE_URL: ${PUBLIC_BASE_URL:-} PASSWORD_RESET_TOKEN_EXPIRE_MINUTES: ${PASSWORD_RESET_TOKEN_EXPIRE_MINUTES:-30} volumes: - - ./backend:/app - ./backend/agent_data:/data/agents - /var/run/docker.sock:/var/run/docker.sock - ./ss-nodes.json:/data/ss-nodes.json:ro + privileged: true cap_add: - SYS_ADMIN security_opt: @@ -106,7 +106,7 @@ services: backend-trigger: build: - context: ./backend + context: ../backend args: CLAWITH_PIP_INDEX_URL: ${CLAWITH_PIP_INDEX_URL:-} CLAWITH_PIP_TRUSTED_HOST: ${CLAWITH_PIP_TRUSTED_HOST:-} @@ -137,7 +137,6 @@ services: PUBLIC_BASE_URL: ${PUBLIC_BASE_URL:-} PASSWORD_RESET_TOKEN_EXPIRE_MINUTES: ${PASSWORD_RESET_TOKEN_EXPIRE_MINUTES:-30} volumes: - - ./backend:/app - ./backend/agent_data:/data/agents - /var/run/docker.sock:/var/run/docker.sock - ./ss-nodes.json:/data/ss-nodes.json:ro diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index 92d4eaeb9..aabfeb584 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -31,7 +31,7 @@ services: backend: build: - context: ./backend + context: ../backend args: CLAWITH_PIP_INDEX_URL: ${CLAWITH_PIP_INDEX_URL:-} CLAWITH_PIP_TRUSTED_HOST: ${CLAWITH_PIP_TRUSTED_HOST:-} @@ -59,10 +59,10 @@ services: # Password reset token lifetime in minutes (default: 30) PASSWORD_RESET_TOKEN_EXPIRE_MINUTES: ${PASSWORD_RESET_TOKEN_EXPIRE_MINUTES:-30} volumes: - - ./backend:/app - ./backend/agent_data:/data/agents - /var/run/docker.sock:/var/run/docker.sock - ./ss-nodes.json:/data/ss-nodes.json:ro + privileged: true cap_add: - SYS_ADMIN security_opt: @@ -80,7 +80,7 @@ services: max-size: "10m" max-file: "3" frontend: - build: ./frontend + build: ../frontend restart: unless-stopped ports: - "${FRONTEND_PORT:-3008}:3000" diff --git a/frontend/src/pages/agent-detail/AgentDetailPage.tsx b/frontend/src/pages/agent-detail/AgentDetailPage.tsx index dd2848080..c815e1aeb 100644 --- a/frontend/src/pages/agent-detail/AgentDetailPage.tsx +++ b/frontend/src/pages/agent-detail/AgentDetailPage.tsx @@ -2005,17 +2005,9 @@ export default function AgentDetailPage() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [agent?.primary_model_id]); - const handleModelChange = useCallback(async (newModelId: string | null) => { + const handleModelChange = useCallback((newModelId: string | null) => { setOverrideModelId(newModelId); - if (!id || !newModelId || newModelId === agent?.primary_model_id) return; - if ((agent as any)?.access_level !== 'manage') return; - try { - await agentApi.update(id, { primary_model_id: newModelId }); - queryClient.invalidateQueries({ queryKey: ['agent', id] }); - } catch { - setOverrideModelId(agent?.primary_model_id || null); - } - }, [id, agent?.primary_model_id, (agent as any)?.access_level, queryClient]); + }, []); // Track onboarding kickoff per (agent, session) so the agent only greets // once per session. The agent opens the conversation itself — no visible