0Pricing
AI Agents · Lección

Envío de mensajes y bloques enriquecidos

Texto sin formato, Markdown y JSON de Block Kit: dé formato a los mensajes de Slack.

Envío de mensajes y bloques enriquecidos es una lección gratuita de AI Agents en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de AI Agents, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de AI Agents incluye 4 lecciones en total.

Mensajes de texto simples con say()

La forma más sencilla de publicar un mensaje en Slack es say(text). El texto admite mrkdwn, la variante de Markdown de Slack. Use *bold*, _italic_, ~strike~, `code` y menciones como <@USERID>.

@app.event('app_mention')
def handle_mention(event, say):
    user = event['user']

    # Simple text response with mrkdwn formatting
    say(
        text=(
            f'Hello <@{user}>!\n'
            '*Agent Report:*\n'
            '- Tasks completed: `42`\n'
            '- Errors: `0`\n'
            '- _Runtime: 3.2 seconds_'
        ),
        mrkdwn=True  # enabled by default
    )

    # Slack mentions
    say(f'<@{user}> your request is being processed')
    say('Posting to <!channel>: all hands meeting tomorrow')

Introducción a Block Kit

Block Kit es el framework de interfaz de Slack para crear mensajes enriquecidos e interactivos. En lugar de texto sin formato, componga los mensajes a partir de bloques tipados: section, header, divider, actions y context. Pase los bloques como una lista al parámetro blocks de say() o chat_postMessage().

@app.event('app_mention')
def handle_mention(event, say):
    blocks = [
        {
            'type': 'header',
            'text': {'type': 'plain_text', 'text': 'Agent Status Report'}
        },
        {
            'type': 'divider'
        },
        {
            'type': 'section',
            'text': {
                'type': 'mrkdwn',
                'text': '*Status:* Running\n*Tasks:* 42 completed'
            }
        }
    ]

    say(
        text='Agent Status Report',  # fallback for notifications
        blocks=blocks
    )

Bloques section con campos de texto

El bloque section es el más versátil. Puede mostrar texto (mrkdwn o plain_text), una lista de pares de clave y valor o un elemento accesorio (botón, imagen o menú de opciones). Use fields para mostrar pares de clave y valor uno junto a otro; son ideales para los paneles.

def build_task_summary_blocks(tasks):
    blocks = [
        {
            'type': 'header',
            'text': {'type': 'plain_text', 'text': 'Daily Task Summary'}
        },
        {
            'type': 'section',
            'text': {
                'type': 'mrkdwn',
                'text': f'Processed *{len(tasks)} tasks* today.'
            }
        },
        {
            'type': 'section',
            'fields': [
                {'type': 'mrkdwn', 'text': f'*Completed:*\n{sum(1 for t in tasks if t["status"]=="done")}'},
                {'type': 'mrkdwn', 'text': f'*Failed:*\n{sum(1 for t in tasks if t["status"]=="error")}'},
                {'type': 'mrkdwn', 'text': f'*Pending:*\n{sum(1 for t in tasks if t["status"]=="pending")}'},
                {'type': 'mrkdwn', 'text': f'*Avg Time:*\n3.2s'}
            ]
        }
    ]
    return blocks

# --- demo ---
tasks = [
    {'status': 'done'}, {'status': 'done'}, {'status': 'error'}, {'status': 'pending'}
]
blocks = build_task_summary_blocks(tasks)
for b in blocks:
    print(b)

Bloques header y divider

Use bloques header para los títulos grandes de las secciones y bloques divider para separar visualmente el contenido. El bloque header solo admite plain_text, no mrkdwn. Combínelos para crear mensajes de informes bien estructurados.

def build_report_message(title, sections):
    blocks = []

    # Header
    blocks.append({
        'type': 'header',
        'text': {'type': 'plain_text', 'text': title, 'emoji': True}
    })

    for section_title, content in sections:
        # Divider between sections
        blocks.append({'type': 'divider'})

        # Section header as bold mrkdwn
        blocks.append({
            'type': 'section',
            'text': {'type': 'mrkdwn', 'text': f'*{section_title}*\n{content}'}
        })

    return blocks

blocks = build_report_message(
    title='Weekly Agent Report',
    sections=[
        ('Emails Processed', '142 emails classified, 38 replies drafted'),
        ('Tasks Completed', '89 tasks completed, 3 failures logged')
    ]
)

# --- demo ---
for b in blocks:
    print(b)

Bloques actions con botones

Los bloques actions contienen elementos interactivos, como botones. Cada botón tiene un action_id (que se usa para dirigir los clics a los controladores), un text y un value opcional que transporta datos. Use style: 'primary' para la acción principal y style: 'danger' para las acciones destructivas.

def build_approval_message(task_id, task_description):
    blocks = [
        {
            'type': 'section',
            'text': {
                'type': 'mrkdwn',
                'text': f'*Task ready for approval:*\n{task_description}'
            }
        },
        {
            'type': 'actions',
            'elements': [
                {
                    'type': 'button',
                    'text': {'type': 'plain_text', 'text': 'Approve'},
                    'style': 'primary',
                    'action_id': 'approve_task',
                    'value': task_id
                },
                {
                    'type': 'button',
                    'text': {'type': 'plain_text', 'text': 'Reject'},
                    'style': 'danger',
                    'action_id': 'reject_task',
                    'value': task_id
                }
            ]
        }
    ]
    return blocks

# --- demo ---
blocks = build_approval_message('task_42', 'Deploy backend v2.3 to production')
for b in blocks:
    print(b)

Bloques context para metadatos

Los bloques context muestran texto pequeño y secundario en la parte inferior de un mensaje; son perfectos para metadatos como marcas de tiempo, fuentes o información sobre la versión del agente. Admiten mrkdwn e imágenes, por ejemplo, para iconos pequeños.

import datetime

def add_context_footer(blocks, agent_version='v1.2'):
    timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M UTC')
    blocks.append({
        'type': 'context',
        'elements': [
            {
                'type': 'mrkdwn',
                'text': f'Generated by Agent {agent_version} | {timestamp}'
            }
        ]
    })
    return blocks

# Full message with context footer
blocks = [
    {
        'type': 'section',
        'text': {'type': 'mrkdwn', 'text': 'Analysis complete. See results below.'}
    }
]
blocks = add_context_footer(blocks)
print(f'Message has {len(blocks)} blocks')

mrkdwn en campos de texto

El mrkdwn de Slack admite un subconjunto de Markdown. Entre las principales opciones de formato para los mensajes del agente se incluyen negrita, cursiva, código, enlaces, menciones de canales, menciones de usuarios y listas. Úselas para que el contenido generado por IA sea fácil de leer en Slack.

def format_ai_response_as_mrkdwn(title, bullet_points, code_snippet=None):
    lines = [f'*{title}*']

    for point in bullet_points:
        lines.append(f'• {point}')

    if code_snippet:
        lines.append(f'```{code_snippet}```')  # code block

    return '\n'.join(lines)

content = format_ai_response_as_mrkdwn(
    title='Security Issues Found',
    bullet_points=[
        'SQL injection risk in `user_search()` function',
        'Hardcoded API key in `config.py` line 42',
        'Missing HTTPS on login endpoint'
    ],
    code_snippet='SELECT * FROM users WHERE id = " + userId + "\n# ^ UNSAFE: use parameterized queries'
)

print(content)

Mensajes efímeros con respond()

Los mensajes efímeros solo son visibles para el usuario que activó la acción, no para los demás miembros del canal. Úselos para actualizaciones de estado, mensajes de error y confirmaciones que no necesiten llenar el canal de contenido. Solo están disponibles mediante respond() (comandos slash) o chat_postEphemeral().

@app.command('/check-status')
def handle_status(ack, respond, body, client):
    ack()
    user_id = body['user_id']
    channel_id = body['channel_id']

    # Ephemeral: only the user who ran /check-status sees this
    respond(
        text='Checking agent status...',
        response_type='ephemeral'
    )

    status = get_agent_status()

    # Or use chat_postEphemeral for more control
    client.chat_postEphemeral(
        channel=channel_id,
        user=user_id,
        text=f'Agent Status: {status}',
        blocks=build_status_blocks(status)
    )

Actualización de mensajes después de enviarlos

Después de publicar un mensaje, puede actualizarlo mediante client.chat_update() con el canal y la marca de tiempo del mensaje (ts). Esto resulta útil para las actualizaciones de progreso: publique un mensaje inicial «Processing...» y, después, actualícelo con el resultado cuando termine.

@app.command('/analyze')
def handle_analyze(ack, say, respond, body, client):
    ack()
    text = body.get('text', '')
    channel = body['channel_id']

    # Post initial message
    initial = client.chat_postMessage(
        channel=channel,
        text='Analyzing... this may take a moment.'
    )
    message_ts = initial['ts']

    # Do the work
    import threading
    def do_work():
        result = slow_ai_analysis(text)
        # Update the original message with the result
        client.chat_update(
            channel=channel,
            ts=message_ts,
            text=f'Analysis complete: {result}',
            blocks=build_result_blocks(result)
        )

    threading.Thread(target=do_work, daemon=True).start()

Publicación en canales específicos

Use client.chat_postMessage(channel=channel_id, text=...) para publicar en cualquier canal al que su bot tenga acceso. Busque los ID de los canales en la API de Slack o haciendo clic con el botón derecho en un canal. Use conversations_list() para buscar canales por nombre mediante programación.

def post_alert_to_channel(client, channel_name, alert_message):
    # Look up channel ID by name
    result = client.conversations_list(
        types='public_channel,private_channel',
        limit=200
    )

    channel_id = None
    for ch in result['channels']:
        if ch['name'] == channel_name:
            channel_id = ch['id']
            break

    if not channel_id:
        print(f'Channel #{channel_name} not found')
        return None

    # Post the alert
    response = client.chat_postMessage(
        channel=channel_id,
        text=alert_message,
        unfurl_links=False,  # don't expand URLs
        unfurl_media=False
    )
    print(f'Posted to #{channel_name}: ts={response["ts"]}')
    return response

# --- demo: minimal stand-in for the Slack client ---
class _FakeClient:
    def conversations_list(self, **kwargs):
        return {'channels': [{'name': 'alerts', 'id': 'C123'}, {'name': 'general', 'id': 'C456'}]}
    def chat_postMessage(self, **kwargs):
        print(f"[slack] postMessage to {kwargs['channel']}: {kwargs['text']}")
        return {'ts': '1699999999.000100'}

post_alert_to_channel(_FakeClient(), 'alerts', 'Disk usage above 90% on web-1')

Patrón de constructor de mensajes de Block Kit

Use una función constructora que acepte datos y devuelva una lista de bloques. Así separará el formato de los mensajes de la lógica de negocio y podrá reutilizar los bloques en distintos controladores de eventos.

def build_alert_blocks(level, title, details, link=None):
    level_emoji = {'info': ':information_source:',
                   'warning': ':warning:', 'error': ':x:'}.get(level, '')

    blocks = [
        {
            'type': 'header',
            'text': {'type': 'plain_text', 'text': f'{level_emoji} {title}'}
        },
        {
            'type': 'section',
            'text': {'type': 'mrkdwn', 'text': details}
        }
    ]

    if link:
        blocks.append({
            'type': 'actions',
            'elements': [{
                'type': 'button',
                'text': {'type': 'plain_text', 'text': 'View Details'},
                'url': link,
                'action_id': 'view_details'
            }]
        })

    import datetime
    blocks.append({
        'type': 'context',
        'elements': [{'type': 'mrkdwn',
                      'text': datetime.datetime.now().strftime('%Y-%m-%d %H:%M UTC')}]
    })
    return blocks

# --- demo ---
blocks = build_alert_blocks('warning', 'High latency', 'p95 latency is 3.2s', link='https://dash.example.com')
for b in blocks:
    print(b)

Comprobación rápida: tipos de bloques

Compruebe sus conocimientos sobre Slack Block Kit.

Repaso de los mensajes enriquecidos

Su agente ahora puede publicar mensajes de Slack profesionales e interactivos:

  • say(text): texto mrkdwn simple; admite *bold*, _italic_, `code` y menciones
  • say(blocks=[...]): Block Kit para diseños estructurados
  • header: título grande de sección, solo plain_text
  • section: cuerpo de texto con campos opcionales (cuadrícula de clave y valor) o un accesorio
  • divider: línea separadora horizontal
  • actions: contenedor para botones y elementos interactivos
  • context: texto pequeño de metadatos en la parte inferior
  • respond(response_type='ephemeral'): mensaje visible únicamente para el usuario que activó la acción
  • chat_update(ts=...): actualiza un mensaje publicado anteriormente con contenido nuevo

Preguntas frecuentes

¿La lección «Envío de mensajes y bloques enriquecidos» es gratis?

Sí — el texto completo de «Envío de mensajes y bloques enriquecidos» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de AI Agents, actualiza a CoddyKit PRO. El curso de AI Agents incluye 4 lecciones en total.

¿Qué aprenderé en «Envío de mensajes y bloques enriquecidos»?

Texto sin formato, Markdown y JSON de Block Kit: dé formato a los mensajes de Slack. Practicas AI Agents con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar AI Agents?

No se requiere experiencia previa. AI Agents en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Envío de mensajes y bloques enriquecidos»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de AI Agents?

Sí. Cada lección de AI Agents incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Fundamentos del SDK Slack Bolt
  2. Escucha de eventos y comandos de barra
  3. Envío de mensajes y bloques enriquecidos
  4. Creación de un bot de notificaciones para equipos
← Volver a AI Agents