smithery/adriangmrraa

Omnichannel Chat Operator

Especialista en gestión de conversaciones multi-canal (WhatsApp, Instagram, Facebook) para Platform AI Solutions.

Installation

$ npx skills add smithery/adriangmrraa --skill omnichannel-chat-operator

Also in this package

Other skills from smithery/adriangmrraa.

npx skills add smithery/adriangmrraa

Browse all from smithery/adriangmrraa

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 10,939 B
  • docs SUMMARY.md 147 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Omnichannel Chat Operator - Platform AI Solutions

1. Arquitectura de Comunicación

Canales Soportados

  • WhatsApp: Via Meta Cloud API o YCloud
  • Instagram: Via Meta Graph API
  • Facebook Messenger: Via Meta Graph API
  • Web Widget: Canal directo (Chatwoot optional)

Flujo Híbrido de Sincronización

Frontend (Chats.tsx)
    ↓
Polling (10s) → GET /admin/chats/summary
    ↓
Chat Selected → Loop (3s) → GET /admin/chats/{id}/messages
    ↓
Delta Sync (solo nuevos mensajes)

2. Gestión de Conversaciones

Cargar Lista de Chats

// Polling cada 10 segundos
const loadChats = async () => {
  const response = await useApi<Contact[]>({
    method: 'GET',
    url: '/admin/chats/summary',
    params: {
      human_filter: 'all',  // 'all', 'human_only', 'bot_only'
      channel: 'whatsapp',  // Filtro opcional
      limit: 20
    }
  });
};

// Response structure
interface Contact {
  id: string;  // UUID
  customer_phone: string;
  display_name: string;
  last_message: string;
  timestamp: string;
  channel_source: 'whatsapp' | 'instagram' | 'facebook' | 'web';
  unread_count: number;
  is_locked: boolean;  // Human override activo
  platform_origin: string;  // Cuenta específica de Meta
}

Cargar Mensajes de Conversación

// Loop de 3 segundos cuando chat está seleccionado
const loadMessages = async (chatId: string) => {
  const messages = await useApi<Message[]>({
    method: 'GET',
    url: `/admin/chats/${chatId}/messages`
  });
  
  // Ordenar por timestamp (puede venir desordenado)
  messages.sort((a, b) => 
    new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
  );
};

// Message structure
interface Message {
  id: number;
  conversation_id: string;
  sender: 'user' | 'agent';
  content: string;
  timestamp: string;
  attachments?: Attachment[];  // Multimedia
  correlation_id?: string;  // Link con logs de IA
}

interface Attachment {
  type: 'image' | 'video' | 'audio' | 'document';
  url: string;
  filename?: string;
}

3. Envío de Mensajes (Unified Outbox)

Send Tunnel

const sendMessage = async (
  conversationId: string,
  message: string,
  channelSource: string
) => {
  await useApi({
    method: 'POST',
    url: '/admin/whatsapp/send',
    data: {
      conversation_id: conversationId,
      message: message,
      channel_source: channelSource  // CRÍTICO para routing
    }
  });
};

Backend Routing (Orchestrator v6.2.9)

# orchestrator_service/app/api/v1/endpoints/chats.py

@router.post("/whatsapp/send")
async def send_message(
    payload: SendMessageRequest,
    current_user = Depends(verify_admin_token)
):
    # 1. Resolver tenant e ID de conversación
    tenant_id = await resolve_tenant(current_user.id)
    
    # 2. Delegar al Universal Delivery Relay (v6.2.9)
    # Se centraliza en whatsapp_service para aplicar Spacing (4s) y Auth Dinámica.
    relay_payload = {
        "to": payload.to_number,
        "text": payload.message,
        "provider": resolve_provider(payload.channel_source),
        "channel_source": payload.channel_source,
        "tenant_id": tenant_id,
        "conversation_id": payload.conversation_id
    }
    
    await delivery_relay.post("/messages/relay", json=relay_payload)
    
    # 3. Guardar en DB para auditoría
    # ... persistencia ...
    
    return {"status": "sent"}

4. Human Override (Intervención Humana)

Activar Chat Lock

const toggleHumanOverride = async (
  chatId: string,
  locked: boolean
) => {
  await useApi({
    method: 'POST',
    url: `/admin/conversations/${chatId}/human-override`,
    data: { locked }
  });
};

Backend Implementation

@router.post("/conversations/{conversation_id}/human-override")
async def set_human_override(
    conversation_id: str,
    payload: HumanOverrideRequest,
    session: AsyncSession = Depends(get_session)
):
    # Actualizar flag
    stmt = update(ChatConversation).where(
        ChatConversation.id == conversation_id
    ).values(is_locked=payload.locked)
    
    await session.execute(stmt)
    await session.commit()
    
    # El bot dejará de responder automáticamente
    # hasta que is_locked = false
    
    return {"locked": payload.locked}

### Detección Automática de Ecos (Chatwoot Dash)
Si un humano responde directamente desde la interfaz de Chatwoot, el `whatsapp_service` captura el evento `message_created` (outgoing) y lo marca como `is_echo = True`. Al llegar al Orchestrator, este activa el bloqueo de IA automáticamente para ese chat.

5. Templates HSM (Meta 24h Window)

Regla de Meta

  • Ventana de 24h: Después de la última interacción del usuario, solo puedes responder con texto libre durante 24 horas
  • Re-enganche: Pasadas 24h, debes usar plantillas HSM pre-aprobadas por Meta

UI Template Selector

interface Template {
  id: string;
  name: string;
  language: string;
  status: 'APPROVED' | 'PENDING' | 'REJECTED';
  category: 'MARKETING' | 'UTILITY' | 'AUTHENTICATION';
  components: TemplateComponent[];
}

const sendTemplate = async (
  conversationId: string,
  templateId: string,
  parameters: string[]
) => {
  await useApi({
    method: 'POST',
    url: '/admin/templates/send',
    data: {
      conversation_id: conversationId,
      template_id: templateId,
      parameters: parameters
    }
  });
};

Sincronizar Templates

# Sync con Meta para obtener status actualizado
@router.post("/templates/sync")
async def sync_templates(tenant_id: int):
    # Obtener credenciales de Meta
    waba_token = await get_tenant_credential(
        tenant_id=tenant_id,
        category="whatsapp_cloud"
    )
    
    # Llamar a Meta Graph API
    response = requests.get(
        f"https://graph.facebook.com/v18.0/{waba_id}/message_templates",
        headers={"Authorization": f"Bearer {waba_token}"}
    )
    
    templates = response.json()['data']
    
    # Actualizar DB local
    for template in templates:
        # Upsert en tabla templates
        pass
    
    return {"synced": len(templates)}

6. Multimedia (Attachments)

Renderizar Adjuntos

const renderAttachment = (attachment: Attachment) => {
  switch (attachment.type) {
    case 'image':
      return <img src={attachment.url} alt="Attachment" />;
    case 'video':
      return <video src={attachment.url} controls />;
    case 'audio':
      return <audio src={attachment.url} controls />;
    case 'document':
      return <a href={attachment.url} download>{attachment.filename}</a>;
  }
};

Backend Storage

# Attachments se guardan como JSONB en chat_messages.attachments
attachments = [
    {
        "type": "image",
        "url": "https://cdn.whatsapp.net/...",
        "mime_type": "image/jpeg"
    }
]

msg = ChatMessage(
    conversation_id=conv_id,
    sender='user',
    content='[Image]',
    attachments=attachments  # JSONB column
)

7. Indicadores Visuales (UI)

Estado Online

const isOnline = (lastInteraction: string): boolean => {
  const diff = Date.now() - new Date(lastInteraction).getTime();
  return diff < 5 * 60 * 1000;  // < 5 minutos = online
};

Borde de Color por Canal

const getBorderColor = (channel: string) => {
  switch (channel) {
    case 'whatsapp': return 'border-green-500';
    case 'instagram': return 'border-pink-500';
    case 'facebook': return 'border-blue-500';
    case 'web': return 'border-purple-500';
  }
};

8. Traceability (Correlation ID)

Link con AI Logs

# Al crear mensaje del agente
correlation_id = str(uuid.uuid4())

msg = ChatMessage(
    conversation_id=conv_id,
    sender='agent',
    content=response,
    correlation_id=correlation_id
)

# En logs del agent_service
logger.info(
    f"AI Response",
    extra={
        "correlation_id": correlation_id,
        "reasoning": reasoning_steps,
        "tools_used": tool_calls
    }
)

Frontend Debugging

// Ver logs de razonamiento del agente
const viewAIReasoning = async (correlationId: string) => {
  const logs = await useApi({
    method: 'GET',
    url: `/admin/logs/ai/${correlationId}`
  });
  // Mostrar en modal
};

9. Paginación y Scroll Infinito

Implementación

const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
  const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
  
  // Detectar bottom
  if (scrollHeight - scrollTop === clientHeight) {
    if (!loading && hasMore) {
      loadMoreChats();
    }
  }
};

const loadMoreChats = async () => {
  const newChats = await useApi({
    method: 'GET',
    url: '/admin/chats/summary',
    params: {
      offset: contacts.length,
      limit: 20
    }
  });
  
  setContacts([...contacts, ...newChats]);
};

10. Troubleshooting

"El bot no responde"

# Checklist de diagnóstico
1. Verificar is_locked = false en chat_conversations
2. Verificar tenant_id del mensaje entrante coincide con agent.tenant_id
3. Verificar credenciales OpenAI válidas para el tenant
4. Revisar logs: docker logs orchestrator_service --tail 100

"Error sending message"

# Causas comunes:
- Falta channel_source en payload
- Token de Meta expirado
- 24h window expirada (usar template)
- Número no registrado en WABA

"Mensajes desordenados"

// SIEMPRE ordenar en frontend
messages.sort((a, b) => 
  new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
);

11. Multi-Tenant Security

Filtrado Obligatorio

# Backend SIEMPRE debe filtrar por tenant
stmt = select(ChatConversation).where(
    ChatConversation.tenant_id == tenant_id
)

# El usuario del tenant 1 NUNCA debe ver chats del tenant 2

12. Checklist de Features

Vista Chats.tsx

  • Polling de conversaciones activo
  • Loop de mensajes cuando chat seleccionado
  • Envío de mensajes con channel_source correcto
  • Toggle human override funcional
  • Renderizado de multimedia (attachments)
  • Paginación con scroll infinito
  • Indicadores visuales (online, canal)
  • Filtros (human_filter, channel)

Backend

  • Routing multi-canal (WhatsApp/IG/FB)
  • Human override persistence
  • Template management
  • Attachment storage (JSONB)
  • Correlation ID logging
  • Multi-tenant isolation
  • Delta sync optimization

Tip: Para debugging en producción, usar correlation_id para trazar el flujo completo desde el mensaje del usuario → razonamiento del agente → respuesta final.