From 03490762bee7d43914da2aeb7df92b62833cef7e Mon Sep 17 00:00:00 2001 From: Viswamedha Nalabotu Date: Sat, 20 Dec 2025 20:40:23 +0000 Subject: [PATCH] Fixed core issues --- apps/agents/tasks.py | 10 ++-- compose/dev/docker-compose.yml | 32 ++++++++++-- compose/dev/python/Dockerfile | 6 ++- compose/prod/docker-compose.local.yml | 51 ++++++++++++++++++++ compose/prod/docker-compose.yml | 17 ++++++- compose/prod/start | 22 +++++++-- config/__pycache__/settings.cpython-313.pyc | Bin 5838 -> 6504 bytes config/settings.py | 43 ++++++++++++----- data/site/agents.json | 18 +++++++ data/site/users.json | 2 +- index.html | 1 - mcp_agent/mcp_client.py | 4 +- requirements/base.txt | 1 + src/lib/api.ts | 14 +++++- 14 files changed, 190 insertions(+), 31 deletions(-) create mode 100644 compose/prod/docker-compose.local.yml create mode 100644 data/site/agents.json diff --git a/apps/agents/tasks.py b/apps/agents/tasks.py index 4b2384b..0685655 100644 --- a/apps/agents/tasks.py +++ b/apps/agents/tasks.py @@ -10,10 +10,10 @@ import asyncio @shared_task def start_agent_task_mcp(execution_id): - print(f"[start_agent_task_mcp] invoked with execution_id={execution_id}") + print(f"invoked with execution_id={execution_id}") try: execution = AgentExecution.objects.get(uuid=execution_id) - print(f"[start_agent_task_mcp] execution record loaded: agent={execution.agent.uuid}") + print(f"execution record loaded: agent={execution.agent.uuid}") execution.status = 'running' execution.started_at = timezone.now() execution.save() @@ -30,7 +30,7 @@ def start_agent_task_mcp(execution_id): "content": { "execution_id": str(execution.uuid), "agent_id": str(execution.agent.uuid), - "message": "Agent execution started (via MCP)" + "message": "Agent execution started" }, "timestamp": timezone.now().isoformat() } @@ -57,7 +57,7 @@ def start_agent_task_mcp(execution_id): ) result = asyncio.run(execute_remote()) - print(f"[start_agent_task_mcp] MCP result: {result.get('status')}") + print(f"MCP result: {result.get('status')}") if result.get('events'): for event in result['events']: @@ -110,7 +110,7 @@ def start_agent_task_mcp(execution_id): except AgentExecution.DoesNotExist: print(f"Execution {execution_id} not found") except Exception as e: - print(f"[start_agent_task_mcp] exception: {e}") + print(f"exception: {e}") import traceback traceback.print_exc() try: diff --git a/compose/dev/docker-compose.yml b/compose/dev/docker-compose.yml index c700d13..600b1c7 100644 --- a/compose/dev/docker-compose.yml +++ b/compose/dev/docker-compose.yml @@ -1,6 +1,21 @@ services: + fyp-postgres: + image: postgres:15-alpine + container_name: ${POSTGRES_CONTAINER_NAME:-fyp-postgres} + env_file: + - ../../.env + environment: + POSTGRES_HOST_AUTH_METHOD: trust + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-fyp}"] + interval: 5s + timeout: 3s + retries: 5 + fyp-redis: image: redis:7-alpine container_name: ${REDIS_CONTAINER_NAME:-fyp-redis} @@ -41,7 +56,6 @@ services: - "0.0.0.0:8000:8000" volumes: - ../../:/app - - venv:/venv environment: DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-dev-secret-key-change-in-production} DJANGO_DEBUG: "true" @@ -49,10 +63,13 @@ services: DJANGO_CELERY_BROKER_URL: redis://${REDIS_CONTAINER_NAME:-fyp-redis}:6379/0 DJANGO_CORS_ALLOWED_ORIGINS: http://localhost:5173,http://127.0.0.1:5173 DJANGO_SETTINGS_MODULE: config.settings - MCP_AGENT_URL: http://mcp-agent-server:8001 + env_file: + - ../../.env depends_on: fyp-redis: condition: service_healthy + fyp-postgres: + condition: service_healthy web: condition: service_started mcp-agent-server: @@ -65,16 +82,18 @@ services: container_name: dynavera-celery volumes: - ../../:/app - - venv:/venv - ${USERPROFILE}/.cache/gpt4all:/root/.cache/gpt4all:rw environment: DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-dev-secret-key-change-in-production} DJANGO_CELERY_BROKER_URL: redis://${REDIS_CONTAINER_NAME:-fyp-redis}:6379/0 DJANGO_SETTINGS_MODULE: config.settings - MCP_AGENT_URL: http://mcp-agent-server:8001 + env_file: + - ../../.env depends_on: fyp-redis: condition: service_healthy + fyp-postgres: + condition: service_healthy mcp-agent-server: condition: service_started @@ -94,10 +113,15 @@ services: DJANGO_SETTINGS_MODULE: config.settings PYTHONUNBUFFERED: "1" HOME: /root + env_file: + - ../../.env depends_on: fyp-redis: condition: service_healthy + fyp-postgres: + condition: service_healthy volumes: redis_data: venv: + postgres_data: diff --git a/compose/dev/python/Dockerfile b/compose/dev/python/Dockerfile index e41afb0..a018e04 100644 --- a/compose/dev/python/Dockerfile +++ b/compose/dev/python/Dockerfile @@ -3,6 +3,7 @@ FROM python:3.12-bookworm RUN apt-get update && apt-get install --no-install-recommends -y \ build-essential \ libpq-dev \ + wait-for-it \ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ && rm -rf /var/lib/apt/lists/* @@ -16,4 +17,7 @@ WORKDIR /app COPY requirements/base.txt . RUN pip install --no-cache-dir --requirement base.txt -CMD ["daphne", "-b", "0.0.0.0", "-p", "8000", "config.asgi:application"] \ No newline at end of file +COPY ./compose/prod/start /start +RUN sed -i 's/\r$//g' /start && chmod +x /start + +CMD ["/start"] \ No newline at end of file diff --git a/compose/prod/docker-compose.local.yml b/compose/prod/docker-compose.local.yml new file mode 100644 index 0000000..ea21ba6 --- /dev/null +++ b/compose/prod/docker-compose.local.yml @@ -0,0 +1,51 @@ +services: + fyp-traefik: + image: traefik:v2.10 + restart: unless-stopped + command: + - "--api.insecure=true" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--entrypoints.mcp.address=:${MCP_PORT:-58001}" + ports: + - "${MCP_PORT:-58001}:${MCP_PORT:-58001}" + - "8080:8080" + volumes: + - "/var/run/docker.sock:/var/run/docker.sock:ro" + networks: + - mcp-internal + + fyp-mcp: + build: + context: ../.. + dockerfile: compose/dev/mcp/Dockerfile + container_name: dynavera-mcp-server + restart: unless-stopped + deploy: + mode: replicated + replicas: 1 + env_file: + - ../../.env + environment: + - MCP_HTTP_HOST=0.0.0.0 + - MCP_HTTP_PORT=8001 + command: python -m mcp_agent.mcp_server + volumes: + - ../../:/app + - ${USERPROFILE}/.cache/gpt4all:/root/.cache/gpt4all:rw + - ../../build/rag_db:/app/build/rag_db:ro + labels: + - "traefik.enable=true" + - "traefik.http.routers.fyp-mcp.rule=Host(`${MCP_DOMAIN}`)" + - "traefik.http.routers.fyp-mcp.entrypoints=mcp" + - "traefik.http.services.fyp-mcp.loadbalancer.server.port=8001" + - "com.centurylinklabs.watchtower.enable=true" + - "com.centurylinklabs.watchtower.scope=fyp" + networks: + - mcp-internal + +networks: + mcp-internal: + driver: bridge + + diff --git a/compose/prod/docker-compose.yml b/compose/prod/docker-compose.yml index 6930458..ff093a4 100644 --- a/compose/prod/docker-compose.yml +++ b/compose/prod/docker-compose.yml @@ -1,6 +1,19 @@ services: + + fyp-postgres: + image: postgres:15-alpine + restart: unless-stopped + env_file: + - ../../.env + environment: + POSTGRES_HOST_AUTH_METHOD: trust + volumes: + - postgres_data:/var/lib/postgresql/data + networks: + - proxy + fyp-web: image: ${IMAGE} restart: unless-stopped @@ -65,4 +78,6 @@ volumes: gitlab-runner-config: name: gitlab-runner-config gitlab-machine-config: - name: gitlab-machine-config \ No newline at end of file + name: gitlab-machine-config + postgres_data: + name: fyp_postgres_data \ No newline at end of file diff --git a/compose/prod/start b/compose/prod/start index 6f2437d..1093810 100644 --- a/compose/prod/start +++ b/compose/prod/start @@ -4,8 +4,24 @@ set -o errexit set -o pipefail set -o nounset +DB_HOST="${POSTGRES_HOST:-localhost}" +DB_PORT="${POSTGRES_PORT:-5432}" + +echo "Waiting for database at ${DB_HOST}:${DB_PORT}..." +wait-for-it ${DB_HOST}:${DB_PORT} --timeout=30 --strict || { + echo "Timed out waiting for database" >&2 + exit 1 +} + +echo "Database is available, continuing startup..." + python manage.py makemigrations -python manage.py migrate -python manage.py loaddata data/site/users.json +python manage.py migrate --noinput + +for fixture in /app/data/site/*.json; do + echo "Loading fixture: $fixture" + python manage.py loaddata "$fixture" +done + python manage.py collectstatic --noinput -exec /usr/local/bin/daphne -b 0.0.0.0 -p 8000 config.asgi:application +exec daphne -b 0.0.0.0 -p 8000 config.asgi:application diff --git a/config/__pycache__/settings.cpython-313.pyc b/config/__pycache__/settings.cpython-313.pyc index b215aa6d149dbd45d631ab2c296a23008240bfa9..5ca86209db357c1a4a5f1d71e1c376e72fe0af8e 100644 GIT binary patch delta 1782 zcmbtUK};K05dFJe9Kd)@)+QK(0fPw`;$0_%kT`J?$E?A`cwxsRLEXx7fPk9>&|jxQ zM5<{|sH&PqTdA$uLyoD`Ln|)5=UP>+(yFdiwK=7|RHDkMx6T^u#7TPUN`Ged&HHcW z&tL8L!9P#%&+PVQf{*Y=JQqK5pLesH)^CPp8J0SX4YtE)hn6wcBoLzd_Wg?%c;iFH z%k9X1mjz_-|5sE z!4z*B`Ls5kK+h;k`zlc{M*Wq@hml|7RKaZ4*klh!`k=qo)d2Wm0FG({5))!z zP-H_4Jqkl~5CW(?3?pcd&6&BN$Vm(xGEZR_L8>VPOvD+&a~-cc*RY8jSGj@aF~%&7 zO&>EM+sWE{(0nh9!Ks><2!1V~4QnIXF)gTxFb=21L)em}1waa4BP82M2uRv6oDo?~ z0{ zQXOpXi_}+{={n{_P4rb}z2*zd&~xrV`8v@R%Zf#3dx>sYW7fzG5|}r>Yj`(kn^0z= ziBu*Posr8;x7HW4w^rBneAzWI9ZgLtnP@VpT$Lv>QwpSE_qKI_^Y<^km0ep|7Z=yp z@-%l{)R%QVx4x!}*RzW^m)Dkbap}5ozxfxY&$wy(+bv>WR6>G^Cvw|FCWYgwm# zM!qFtHSw(}gRu|o{@(Hz6D~IcHlnDB$wX@F&}u%v5tgK_Ml;YcikB_P>}HPK5y)0U zc4aiT3!Md5Oi`gWfc>7J?23UJ&!p9PNaI-Q(U_uKPRN<5 zbb3}vB^Sy%~pQ(wry}V^#Uw8?QPReCZ6@%y% zIU`?@)rE{I&&|t_E?cu38+d5}w#=CqPm?$e-TWgPp9z<2I~bV13jHI_cq+WtTH;&p z<=)SIYJYI|F+aL(+g)|uVHyP@jBoRMjk~|OK4A)vTZgypPlWDmN2$YGBuAcD?K?Mj z-YjyRB`d#kcjtDI>)LCuxY;6c?KP7_{C{U#h#M7LrH<~87m7qEwRhp$6HiZ(w3j^H zrtR{5(NrXDr8dk6C9khY-tj!OG?qB`&s@(BT+f5Sha(TYUoRJX&;7_n{y+Q^7ujnf cT+=_#RvO6RNmg&c={&M~lBcYXMw-$73(E1T)&Kwi delta 1133 zcmaJ=O-vg{6rPz~!jG|IW8?UTzr}#<;Qb-k{FpdkjDt;#P4=}(X-Be9+JGerbk?b= zC@Qq-DTx%JJw%l%C5Ik*$)WPKr&hT|l`9en`IJ+XLk_KS>aDX*aD^&$q5vAr6#l{$d7t(vL1;CI&?mzuJZoe%gpdslAw$@~JBalh7Up}$PLBWe%wz5m zf13l&CWyI3B*6(T^F9f=duRu^Wg9{XPHruB&bqnp;dt*U+y`DbrxNB@5%{iR7U15` zeUSSA_kGk)12Siz!KUrAEbE6L8-PAG$Zz%YTSL_2Krk>#nAD60c{JRNhIkaBqTXY5 zVSYtivl0xqx*CBHjKC-zQL%<$Od%R(qY&n-5r}eo{;GwKE24_on5DoT1G$wQwh*_% zHL0gGMJ!y<64-nrNWuj7KJoHC#9N6m2+=T&&?r4m$7u`_Fr~Ef(lQN$ocsu(jShrB zrV*G{2$dle=FP(l%tBJ*4KW4g;398q4pL2fscGjmtcpy91*SooO+bWQ;Cm7lA)^vd zmsAW{g|IjsVF|d*reK*(Lyjw(fgGFVJIT}Lc*;e{vs6><3S4P5eaS-1&)YgbPGL5G zGCdnE{%hv{e-7CKCrwjFD@WjJ1h%*-YzhWBnX;QGx@!J-=9?kU(n`9xTq>svh0^ux zQaM+G51`Sxy?bM0du!LI*7WvK(fq-7j3x6{_g}u|L@4|VHEc$8qguIfv$Fk}!6fr* zdkQPHU+e)gb-Q<~THQ;kYKtW~qiGY3;QLyck`AqcB|X2KFG4h9I-OtE?m7FhXTYL& zWOC_ZFm=@&x$I5_+$^?m9m_fb%;i@sxje;s*W2_46g*dOBPp8^s) a|9-nKBG)o8x_N - Dynavera diff --git a/mcp_agent/mcp_client.py b/mcp_agent/mcp_client.py index 1a29b35..6976242 100644 --- a/mcp_agent/mcp_client.py +++ b/mcp_agent/mcp_client.py @@ -11,7 +11,7 @@ logger = logging.getLogger(__name__) class MCPAgentClient: def __init__(self, server_url: Optional[str] = None): - self.server_url = server_url or getattr(settings, 'MCP_AGENT_URL', 'http://localhost:8001') + self.server_url = server_url or getattr(settings, 'MCP_AGENT_URL') self.http_client = httpx.AsyncClient( timeout=httpx.Timeout(300.0), follow_redirects=True @@ -114,7 +114,7 @@ async def get_mcp_client() -> MCPAgentClient: async with _client_lock: if _mcp_client_instance is None: - server_url = getattr(settings, 'MCP_AGENT_URL', 'http://localhost:8001') + server_url = getattr(settings, 'MCP_AGENT_URL') _mcp_client_instance = MCPAgentClient(server_url=server_url) return _mcp_client_instance diff --git a/requirements/base.txt b/requirements/base.txt index 05353b1..3c47bba 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -10,6 +10,7 @@ django-celery-results==2.5.1 django-celery-beat==2.8.1 gunicorn==23.0.0 jinja2==3.1.6 +psycopg2-binary==2.9.10 python-dotenv==1.2.1 requests==2.32.5 sqlparse==0.5.3 diff --git a/src/lib/api.ts b/src/lib/api.ts index 6004d7d..7c15ba7 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -8,8 +8,18 @@ class ApiClient { } private getCsrfToken(): string { - const match = document.cookie.match(/(?:^|; )csrftoken=([^;]+)/); - return match ? decodeURIComponent(match[1]) : ''; + let cookieValue = ''; + if (document.cookie && document.cookie !== '') { + const cookies = document.cookie.split(';'); + for (let i = 0; i < cookies.length; i++) { + const cookie = cookies[i].trim(); + if (cookie.substring(0, 10) === 'csrftoken=') { + cookieValue = decodeURIComponent(cookie.substring(10)); + break; + } + } + } + return cookieValue; } private withCsrf(config?: AxiosRequestConfig): AxiosRequestConfig {