Fixed core issues

This commit is contained in:
Viswamedha Nalabotu 2025-12-20 20:40:23 +00:00
parent c4d220a294
commit 03490762be
14 changed files with 190 additions and 31 deletions

View file

@ -10,10 +10,10 @@ import asyncio
@shared_task @shared_task
def start_agent_task_mcp(execution_id): 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: try:
execution = AgentExecution.objects.get(uuid=execution_id) 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.status = 'running'
execution.started_at = timezone.now() execution.started_at = timezone.now()
execution.save() execution.save()
@ -30,7 +30,7 @@ def start_agent_task_mcp(execution_id):
"content": { "content": {
"execution_id": str(execution.uuid), "execution_id": str(execution.uuid),
"agent_id": str(execution.agent.uuid), "agent_id": str(execution.agent.uuid),
"message": "Agent execution started (via MCP)" "message": "Agent execution started"
}, },
"timestamp": timezone.now().isoformat() "timestamp": timezone.now().isoformat()
} }
@ -57,7 +57,7 @@ def start_agent_task_mcp(execution_id):
) )
result = asyncio.run(execute_remote()) 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'): if result.get('events'):
for event in result['events']: for event in result['events']:
@ -110,7 +110,7 @@ def start_agent_task_mcp(execution_id):
except AgentExecution.DoesNotExist: except AgentExecution.DoesNotExist:
print(f"Execution {execution_id} not found") print(f"Execution {execution_id} not found")
except Exception as e: except Exception as e:
print(f"[start_agent_task_mcp] exception: {e}") print(f"exception: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
try: try:

View file

@ -1,6 +1,21 @@
services: 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: fyp-redis:
image: redis:7-alpine image: redis:7-alpine
container_name: ${REDIS_CONTAINER_NAME:-fyp-redis} container_name: ${REDIS_CONTAINER_NAME:-fyp-redis}
@ -41,7 +56,6 @@ services:
- "0.0.0.0:8000:8000" - "0.0.0.0:8000:8000"
volumes: volumes:
- ../../:/app - ../../:/app
- venv:/venv
environment: environment:
DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-dev-secret-key-change-in-production} DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-dev-secret-key-change-in-production}
DJANGO_DEBUG: "true" DJANGO_DEBUG: "true"
@ -49,10 +63,13 @@ services:
DJANGO_CELERY_BROKER_URL: redis://${REDIS_CONTAINER_NAME:-fyp-redis}:6379/0 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_CORS_ALLOWED_ORIGINS: http://localhost:5173,http://127.0.0.1:5173
DJANGO_SETTINGS_MODULE: config.settings DJANGO_SETTINGS_MODULE: config.settings
MCP_AGENT_URL: http://mcp-agent-server:8001 env_file:
- ../../.env
depends_on: depends_on:
fyp-redis: fyp-redis:
condition: service_healthy condition: service_healthy
fyp-postgres:
condition: service_healthy
web: web:
condition: service_started condition: service_started
mcp-agent-server: mcp-agent-server:
@ -65,16 +82,18 @@ services:
container_name: dynavera-celery container_name: dynavera-celery
volumes: volumes:
- ../../:/app - ../../:/app
- venv:/venv
- ${USERPROFILE}/.cache/gpt4all:/root/.cache/gpt4all:rw - ${USERPROFILE}/.cache/gpt4all:/root/.cache/gpt4all:rw
environment: environment:
DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-dev-secret-key-change-in-production} 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_CELERY_BROKER_URL: redis://${REDIS_CONTAINER_NAME:-fyp-redis}:6379/0
DJANGO_SETTINGS_MODULE: config.settings DJANGO_SETTINGS_MODULE: config.settings
MCP_AGENT_URL: http://mcp-agent-server:8001 env_file:
- ../../.env
depends_on: depends_on:
fyp-redis: fyp-redis:
condition: service_healthy condition: service_healthy
fyp-postgres:
condition: service_healthy
mcp-agent-server: mcp-agent-server:
condition: service_started condition: service_started
@ -94,10 +113,15 @@ services:
DJANGO_SETTINGS_MODULE: config.settings DJANGO_SETTINGS_MODULE: config.settings
PYTHONUNBUFFERED: "1" PYTHONUNBUFFERED: "1"
HOME: /root HOME: /root
env_file:
- ../../.env
depends_on: depends_on:
fyp-redis: fyp-redis:
condition: service_healthy condition: service_healthy
fyp-postgres:
condition: service_healthy
volumes: volumes:
redis_data: redis_data:
venv: venv:
postgres_data:

View file

@ -3,6 +3,7 @@ FROM python:3.12-bookworm
RUN apt-get update && apt-get install --no-install-recommends -y \ RUN apt-get update && apt-get install --no-install-recommends -y \
build-essential \ build-essential \
libpq-dev \ libpq-dev \
wait-for-it \
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
@ -16,4 +17,7 @@ WORKDIR /app
COPY requirements/base.txt . COPY requirements/base.txt .
RUN pip install --no-cache-dir --requirement base.txt RUN pip install --no-cache-dir --requirement base.txt
CMD ["daphne", "-b", "0.0.0.0", "-p", "8000", "config.asgi:application"] COPY ./compose/prod/start /start
RUN sed -i 's/\r$//g' /start && chmod +x /start
CMD ["/start"]

View file

@ -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

View file

@ -1,6 +1,19 @@
services: 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: fyp-web:
image: ${IMAGE} image: ${IMAGE}
restart: unless-stopped restart: unless-stopped
@ -65,4 +78,6 @@ volumes:
gitlab-runner-config: gitlab-runner-config:
name: gitlab-runner-config name: gitlab-runner-config
gitlab-machine-config: gitlab-machine-config:
name: gitlab-machine-config name: gitlab-machine-config
postgres_data:
name: fyp_postgres_data

View file

@ -4,8 +4,24 @@ set -o errexit
set -o pipefail set -o pipefail
set -o nounset 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 makemigrations
python manage.py migrate python manage.py migrate --noinput
python manage.py loaddata data/site/users.json
for fixture in /app/data/site/*.json; do
echo "Loading fixture: $fixture"
python manage.py loaddata "$fixture"
done
python manage.py collectstatic --noinput 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

View file

@ -10,6 +10,7 @@ BUILD_DIR = os.getenv('DJANGO_BUILD_DIR', BASE_DIR / 'build')
SECRET_KEY = os.getenv('DJANGO_SECRET_KEY') SECRET_KEY = os.getenv('DJANGO_SECRET_KEY')
DEBUG = str(os.getenv('DJANGO_DEBUG')).lower() in ('1', 'true', 'yes', 'on') DEBUG = str(os.getenv('DJANGO_DEBUG')).lower() in ('1', 'true', 'yes', 'on')
DOMAIN_NAME = os.getenv('DOMAIN_NAME', 'localhost')
ALLOWED_HOSTS = [stripped_host for host in os.getenv('DJANGO_ALLOWED_HOSTS', 'localhost').split(',') if (stripped_host:=host.strip())] ALLOWED_HOSTS = [stripped_host for host in os.getenv('DJANGO_ALLOWED_HOSTS', 'localhost').split(',') if (stripped_host:=host.strip())]
@ -76,6 +77,8 @@ CHANNEL_LAYERS = {
}, },
} }
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', 'BACKEND': 'django.template.backends.django.DjangoTemplates',
@ -93,11 +96,11 @@ TEMPLATES = [
DB_ENGINE = os.getenv('DJANGO_DB_ENGINE', 'django.db.backends.sqlite3') DB_ENGINE = os.getenv('DJANGO_DB_ENGINE', 'django.db.backends.sqlite3')
DB_NAME = os.getenv('DJANGO_DB_NAME', BASE_DIR / 'db.sqlite3') DB_NAME = os.getenv('POSTGRES_DB', BASE_DIR / 'db.sqlite3')
DB_USER = os.getenv('DJANGO_DB_USER') DB_USER = os.getenv('POSTGRES_USER')
DB_PASSWORD = os.getenv('DJANGO_DB_PASSWORD') DB_PASSWORD = os.getenv('POSTGRES_PASSWORD')
DB_HOST = os.getenv('DJANGO_DB_HOST') DB_HOST = os.getenv('POSTGRES_HOST')
DB_PORT = os.getenv('DJANGO_DB_PORT', 5432) DB_PORT = os.getenv('POSTGRES_PORT', 5432)
DATABASES = { DATABASES = {
'default': { 'default': {
@ -164,14 +167,32 @@ CELERY_TIMEZONE = 'UTC'
CELERY_TASK_TRACK_STARTED = True CELERY_TASK_TRACK_STARTED = True
CELERY_TASK_TIME_LIMIT = 30 * 60 CELERY_TASK_TIME_LIMIT = 30 * 60
MCP_AGENT_URL = os.getenv('MCP_AGENT_URL', 'http://localhost:8001') MCP_AGENT_URL = os.getenv('MCP_AGENT_URL')
if origins:=os.getenv('DJANGO_CORS_ALLOWED_ORIGINS'): X_FRAME_OPTIONS = 'SAMEORIGIN'
CORS_ALLOWED_ORIGINS = origins.split(',')
CORS_ALLOW_CREDENTIALS = True CORS_ALLOW_CREDENTIALS = True
CORS_ALLOWED_ORIGINS = [
f'http://{DOMAIN_NAME}',
f'https://{DOMAIN_NAME}',
]
CSRF_TRUSTED_ORIGINS = [
f'http://{DOMAIN_NAME}',
f'https://{DOMAIN_NAME}',
]
if trusted_origins:=os.getenv('DJANGO_CSRF_TRUSTED_ORIGINS'):
CSRF_TRUSTED_ORIGINS = [origin.strip() for origin in trusted_origins.split(',')] CSRF_COOKIE_HTTPONLY = False
CSRF_COOKIE_SECURE = not DEBUG
CSRF_COOKIE_SAMESITE = 'Lax'
SESSION_COOKIE_SAMESITE = 'Lax'
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = not DEBUG
SESSION_COOKIE_AGE = 1209600
SESSION_SAVE_EVERY_REQUEST = True
if DEBUG: if DEBUG:
SECURE_CROSS_ORIGIN_OPENER_POLICY = None CORS_ALLOWED_ORIGINS.append(f'http://{DOMAIN_NAME}:5173')
CORS_ALLOWED_ORIGINS.append(f'http://{DOMAIN_NAME}:8000')
CSRF_TRUSTED_ORIGINS.append(f'http://{DOMAIN_NAME}:5173')
CSRF_TRUSTED_ORIGINS.append(f'http://{DOMAIN_NAME}:8000')

18
data/site/agents.json Normal file
View file

@ -0,0 +1,18 @@
[
{
"model": "agents.agent",
"pk": 1,
"fields": {
"uuid": "bc5ec7f0-a894-420f-b85b-bc799334eca7",
"user": 1,
"name": "Test Agent",
"description": "General Purpose Agent",
"status": "idle",
"task_id": null,
"created_at": "2025-12-20T20:29:57.607Z",
"updated_at": "2025-12-20T20:29:57.607Z",
"started_at": null,
"completed_at": null
}
}
]

View file

@ -18,7 +18,7 @@
"avatar_url": "", "avatar_url": "",
"is_active": true, "is_active": true,
"is_staff": true, "is_staff": true,
"role": "employee", "role": "manager",
"groups": [], "groups": [],
"user_permissions": [] "user_permissions": []
} }

View file

@ -6,7 +6,6 @@
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Dynavera</title> <title>Dynavera</title>
</head> </head>

View file

@ -11,7 +11,7 @@ logger = logging.getLogger(__name__)
class MCPAgentClient: class MCPAgentClient:
def __init__(self, server_url: Optional[str] = None): 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( self.http_client = httpx.AsyncClient(
timeout=httpx.Timeout(300.0), timeout=httpx.Timeout(300.0),
follow_redirects=True follow_redirects=True
@ -114,7 +114,7 @@ async def get_mcp_client() -> MCPAgentClient:
async with _client_lock: async with _client_lock:
if _mcp_client_instance is None: 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) _mcp_client_instance = MCPAgentClient(server_url=server_url)
return _mcp_client_instance return _mcp_client_instance

View file

@ -10,6 +10,7 @@ django-celery-results==2.5.1
django-celery-beat==2.8.1 django-celery-beat==2.8.1
gunicorn==23.0.0 gunicorn==23.0.0
jinja2==3.1.6 jinja2==3.1.6
psycopg2-binary==2.9.10
python-dotenv==1.2.1 python-dotenv==1.2.1
requests==2.32.5 requests==2.32.5
sqlparse==0.5.3 sqlparse==0.5.3

View file

@ -8,8 +8,18 @@ class ApiClient {
} }
private getCsrfToken(): string { private getCsrfToken(): string {
const match = document.cookie.match(/(?:^|; )csrftoken=([^;]+)/); let cookieValue = '';
return match ? decodeURIComponent(match[1]) : ''; 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 { private withCsrf(config?: AxiosRequestConfig): AxiosRequestConfig {