add-reactions
Add WhatsApp emoji reaction support — receive, send, store, and search reactions.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Add WhatsApp emoji reaction support — receive, send, store, and search reactions.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Redactar escritos jurídicos mexicanos largos (recursos de apelación, demandas, contestaciones, amparos) a partir de varios documentos de un expediente (demanda, contestación, pericial, confesional, sentencia), entregados como .docx editable. Úsalo cuando el usuario pida "recurso de apelación", "redacta el escrito", "haz la demanda/contestación en Word", o cualquier pieza procesal larga que deba correlacionar agravios/hechos con documentos fuente y jurisprudencia verificada.
Sintetizar o redactar un entregable a partir de varios documentos fuente (o pocos muy grandes) que juntos NO caben en la ventana de contexto — reportes multi-fuente, due diligence, análisis/comparación de contratos, resúmenes de expediente, investigación. Úsalo cuando debas correlacionar información entre múltiples documentos y producir un documento nuevo, y leerlos todos completos reventaría el contexto ("Prompt is too long"). NO es para leer un solo documento corto.
Busca y descarga assets de diseño (iconos, ilustraciones, 3D, animaciones Lottie, imágenes AI) desde IconScout. Dispara cuando el user pida un icono/ilustración/animación para un diseño, mockup, presentación o web, o mencione IconScout. 13.8M+ assets con licencia royalty-free.
Text-to-speech with Spanish voices (Kokoro, local & free) and OpenAI fallback
Transcribe a texto el HABLA de un audio largo o pesado (reuniones, notas de voz reenviadas, grabaciones de 10–60+ min). Trocea con ffmpeg y transcribe cada parte con Whisper, sin toparse con el límite de 25MB de la API. Úsala cuando llegue un [Audio file: ...] y el usuario pida "transcribe", "qué dice", "analiza el audio", o para resumir/analizar una grabación de voz.
Haz una versión nueva/ejecutiva/más limpia de un documento institucional (PDFs tipo "orden del día", agendas, hojas de evento, programas) MINANDO sus assets reales (logos, fotos de ponentes, texto, fuentes) y RECONSTRUYENDO en HTML — nunca re-difundiendo la página como imagen. Úsala ante "haz una nueva versión", "versión ejecutiva", "rehazlo más limpio", "adáptalo" de un PDF.
| name | add-reactions |
| description | Add WhatsApp emoji reaction support — receive, send, store, and search reactions. |
This skill adds emoji reaction support to NanoClaw's WhatsApp channel: receive and store reactions, send reactions from the container agent via MCP tool, and query reaction history from SQLite.
Check if src/status-tracker.ts exists:
test -f src/status-tracker.ts && echo "Already applied" || echo "Not applied"
If already applied, skip to Phase 3 (Verify).
git remote -v
If whatsapp is missing, add it:
git remote add whatsapp https://github.com/qwibitai/nanoclaw-whatsapp.git
git fetch whatsapp skill/reactions
git merge whatsapp/skill/reactions || {
git checkout --theirs package-lock.json
git add package-lock.json
git merge --continue
}
This adds:
scripts/migrate-reactions.ts (database migration for reactions table with composite PK and indexes)src/status-tracker.ts (forward-only emoji state machine for message lifecycle signaling, with persistence and retry)src/status-tracker.test.ts (unit tests for StatusTracker)container/skills/reactions/SKILL.md (agent-facing documentation for the react_to_message MCP tool)src/db.ts, src/channels/whatsapp.ts, src/types.ts, src/ipc.ts, src/index.ts, src/group-queue.ts, and container/agent-runner/src/ipc-mcp-stdio.tsnpx tsx scripts/migrate-reactions.ts
npm test
npm run build
All tests must pass and build must be clean before proceeding.
npm run build
Linux:
systemctl --user restart nanoclaw
macOS:
launchctl kickstart -k gui/$(id -u)/com.nanoclaw
sqlite3 store/messages.db "SELECT * FROM reactions ORDER BY timestamp DESC LIMIT 5;"
Ask the agent to react to a message via the react_to_message MCP tool. Check your phone — the reaction should appear on the message.
In groups that require a trigger (requiresTrigger !== false and trigger !== '.*'), the 👀 acknowledgment fires only on the message that individually invoked the bot — not on every message in the processing batch. Context messages stay silent so the bot doesn't spam reactions on every comment in a group where it's one of many participants.
Main groups (trigger: '.*') keep reacting to every user message.
This mirrors OpenClaw's ackReaction.group: "mentions" mode (see docs.openclaw.ai/channels/whatsapp).
Without this filter, a single batch like ["@bot summarize", "lol", "agreed", "👍"] produces four 👀 reactions because all four advance through the message loop together. Users perceive it as the bot "watching" every comment in the group, even when it wasn't invoked.
src/index.ts derives an isInvokingMessage(msg) predicate once per turn, then uses it both for the trigger gate (some) and the markReceived loop (filter):
const needsTrigger = group.requiresTrigger !== false && group.trigger !== '.*';
const triggerPattern = needsTrigger ? getTriggerPattern(group.trigger) : null;
const stickerTrigger = group.containerConfig?.stickerTrigger !== false;
const allowlistCfg = loadSenderAllowlist();
const isInvokingMessage = (m): boolean => {
if (!needsTrigger) return true; // main group: react to everything
return (
(triggerPattern!.test(m.content.trim()) ||
(stickerTrigger && m.content.includes('[Sticker:'))) &&
((ASSISTANT_HAS_OWN_NUMBER && m.is_from_me) ||
isTriggerAllowed(chatJid, m.sender, allowlistCfg))
);
};
// Trigger gate: at least one invoking message present?
if (needsTrigger && !messages.some(isInvokingMessage)) return;
// Ack loop: only the invokers get 👀
for (const msg of messages) {
if (msg.is_from_me || msg.is_bot_message) continue;
if (!isInvokingMessage(msg)) continue;
statusTracker.markReceived(msg.id, chatJid, false, msg.sender);
}
The same predicate must be applied in both call sites where markReceived fires:
processGroupMessages (recovery / direct queue path)startMessageLoop poll cycleIf you only patch one of them, recovery messages or piped batches will leak reactions.
markThinking/markDone/markFailed use forward-only transitions, so non-tracked context messages no-op safely — no extra filtering needed downstream.is_from_me || is_bot_message filter still excludes the bot's own messages (linked-device siblings in shared-number setups, plus bot-prefixed media).stickerTrigger and the sender allowlist participate in the predicate, so sticker-triggered turns and allowlisted senders still get their 👀.81feb6a feat(reactions): only react to invoking message, not whole batch — adds the predicate-based filter to both call sites in src/index.ts. If your skill branch was forked before this commit, apply the pattern manually using the snippet above.
Failed to process reaction errorsstore/messages.db exists and is accessibleUnauthorized IPC reaction attempt blocked — the agent can only react in its own group's chat