Ekaropolus d4b56e1a2c
All checks were successful
continuous-integration/drone/push Build is passing
Internet of Agent Initial part
2025-09-18 12:49:31 -06:00

99 lines
3.2 KiB
Python

from django.http import JsonResponse
from django.views.decorators.http import require_GET
try:
from pxy_contracts.version import SPEC_VERSION
except Exception:
SPEC_VERSION = '0.1.0'
@require_GET
def agents_list(request):
base = request.build_absolute_uri('/')[:-1] # absolute base, no trailing slash
agents = [
{
'agent': 'sami',
'name': 'SAMI-Agent',
'version': '1.0.0',
'spec_version': SPEC_VERSION,
'contracts_url': f'{base}/api/contracts/sami.json',
'execute_url': f'{base}/api/agents/execute',
'description': 'Urban scaling (β,R²) + SAMI residuals + chart',
},
{
'agent': 'sites',
'name': 'Sites-Agent',
'version': '1.0.0',
'spec_version': SPEC_VERSION,
'contracts_url': f'{base}/api/contracts/sites.json',
'execute_url': f'{base}/api/agents/execute',
'description': 'Site scoring (access, demand, competition) with maps',
},
]
return JsonResponse({'agents': agents})
import json
import requests
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from django.http import JsonResponse
from django.conf import settings
# Internal base where your existing APIs live (same host in MVP)
AGENTS_INTERNAL_BASE = getattr(settings, "AGENTS_INTERNAL_BASE", "") # empty = use same host via relative path
@csrf_exempt
@require_POST
def agents_execute(request):
"""
POST /api/agents/execute
Body: { "agent": "sami"|"sites", "payload": {...} }
Proxies to: /api/sami/run or /api/sites/search
"""
try:
body = json.loads(request.body.decode("utf-8"))
agent = (body.get("agent") or "").strip().lower()
payload = body.get("payload")
if agent not in ("sami", "sites"):
return JsonResponse(
{"code": "AGENT_NOT_FOUND", "message": f"unknown agent '{agent}'"},
status=404,
)
if payload is None:
return JsonResponse(
{"code": "BAD_REQUEST", "message": "missing 'payload'"},
status=400,
)
# Resolve proxy target
if agent == "sami":
path = "/api/sami/run"
else:
path = "/api/sites/search"
url = (AGENTS_INTERNAL_BASE or "").rstrip("/") + path
# Absolute self-call (same container) using the request host
if not url.startswith("http"):
base = request.build_absolute_uri("/")[:-1]
url = f"{base}{path}"
r = requests.post(url, json=payload, timeout=90)
# Pass through JSON and status code
return JsonResponse(r.json(), status=r.status_code, safe=False)
except requests.Timeout:
return JsonResponse(
{"code": "UPSTREAM_TIMEOUT", "message": "agent upstream timed out"},
status=504,
)
except ValueError as ve:
return JsonResponse(
{"code": "BAD_JSON", "message": str(ve)},
status=400,
)
except Exception as e:
return JsonResponse(
{"code": "AGENT_EXEC_ERROR", "message": str(e)},
status=500,
)