First commit

This commit is contained in:
2026-06-19 22:17:09 -03:00
commit 239203ee2a
533 changed files with 75195 additions and 0 deletions

View File

@@ -0,0 +1,112 @@
from __future__ import annotations
import logging
from uuid import uuid4
from fastapi import FastAPI, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
from app.adapters.web import WebAdapter
from app.adapters.whatsapp import WhatsAppAdapter
from app.adapters.voice import VoiceAdapter
from app.client import AgentFrameworkClient
from app.schemas import GatewayRequest, VoiceTranscript, WebMessage, WhatsAppWebhook
from app.settings import settings
logging.basicConfig(level=settings.LOG_LEVEL)
logger = logging.getLogger('external_channel_gateway')
app = FastAPI(title='External Channel Gateway')
app.add_middleware(
CORSMiddleware,
allow_origins=[o.strip() for o in settings.CORS_ORIGINS.split(',')],
allow_credentials=True,
allow_methods=['*'],
allow_headers=['*'],
)
client = AgentFrameworkClient()
web_adapter = WebAdapter()
whatsapp_adapter = WhatsAppAdapter()
voice_adapter = VoiceAdapter()
def _require_mode(expected: str, endpoint_type: str):
if settings.runtime_mode != expected:
raise HTTPException(
status_code=409,
detail={
'error_code': 'CHANNEL_GATEWAY_MODE_MISMATCH',
'message': f'{endpoint_type} endpoints require CHANNEL_GATEWAY_RUNTIME_MODE={expected}',
'current_runtime_mode': settings.runtime_mode,
},
)
async def _forward(request: GatewayRequest) -> dict:
return await client.send(request)
@app.get('/health')
async def health():
return {
'status': 'ok',
'app_name': settings.APP_NAME,
'runtime_mode': settings.runtime_mode,
'configured_runtime_mode': settings.CHANNEL_GATEWAY_RUNTIME_MODE,
'legacy_channel_gateway_mode': settings.CHANNEL_GATEWAY_MODE,
'backend_url': client.url,
'default_tenant_id': settings.DEFAULT_TENANT_ID,
'default_agent_id': settings.DEFAULT_AGENT_ID,
}
@app.post('/channels/web/message')
async def web_message(payload: WebMessage, request: Request):
_require_mode('adapter', '/channels/*')
gateway_request = await web_adapter.to_gateway_request(payload)
gateway_request.payload.setdefault('metadata', {})
gateway_request.payload['metadata'].update({
'channel_gateway_request_id': request.headers.get('x-request-id') or str(uuid4()),
'channel_gateway_endpoint': '/channels/web/message',
})
return await _forward(gateway_request)
@app.post('/channels/whatsapp/webhook')
async def whatsapp_webhook(payload: WhatsAppWebhook, request: Request):
_require_mode('adapter', '/channels/*')
try:
gateway_request = await whatsapp_adapter.to_gateway_request(payload)
except ValueError as exc:
raise HTTPException(status_code=422, detail=str(exc)) from exc
gateway_request.payload.setdefault('metadata', {})
gateway_request.payload['metadata'].update({
'channel_gateway_request_id': request.headers.get('x-request-id') or str(uuid4()),
'channel_gateway_endpoint': '/channels/whatsapp/webhook',
})
return await _forward(gateway_request)
@app.post('/channels/voice/transcript')
async def voice_transcript(payload: VoiceTranscript, request: Request):
_require_mode('adapter', '/channels/*')
gateway_request = await voice_adapter.to_gateway_request(payload)
gateway_request.payload.setdefault('metadata', {})
gateway_request.payload['metadata'].update({
'channel_gateway_request_id': request.headers.get('x-request-id') or str(uuid4()),
'channel_gateway_endpoint': '/channels/voice/transcript',
})
return await _forward(gateway_request)
@app.post('/gateway/message')
async def proxy_gateway_message(payload: GatewayRequest, request: Request):
_require_mode('proxy', '/gateway/message')
payload.payload.setdefault('metadata', {})
payload.payload['metadata'].update({
'channel_gateway_request_id': request.headers.get('x-request-id') or str(uuid4()),
'channel_gateway_endpoint': '/gateway/message',
'proxied_by': settings.APP_NAME,
})
return await _forward(payload)