feat(signal): show status reactions during inbound replies#98791
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 3, 2026, 7:35 AM ET / 11:35 UTC. Summary PR surface: Source +232, Tests +1152, Docs +19, Generated 0. Total +1403 across 12 files. Reproducibility: yes. source-level: current main lacks Signal status-reaction controller wiring in the inbound dispatch path, while this PR adds it behind explicit gates. I did not rerun a live Signal setup in this read-only review. Review metrics: 1 noteworthy metric.
Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the focused Signal-plugin implementation after maintainers explicitly accept the opt-in upgrade behavior, keeping lifecycle state in the shared controller and Signal target mapping in the plugin. Do we have a high-confidence way to reproduce the issue? Yes, source-level: current main lacks Signal status-reaction controller wiring in the inbound dispatch path, while this PR adds it behind explicit gates. I did not rerun a live Signal setup in this read-only review. Is this the best way to solve the issue? Yes, this is the best owner-boundary shape: Signal owns timestamp and target mapping while lifecycle state stays in the shared status-reaction controller. The remaining question is maintainer acceptance of the opt-in upgrade behavior change. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against b52d98861e8c. Label changesLabel justifications:
Evidence reviewedPR surface: Source +232, Tests +1152, Docs +19, Generated 0. Total +1403 across 12 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
58cd1d3 to
49547ae
Compare
49547ae to
bff8142
Compare
|
/clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
/clawsweeper re-review |
1 similar comment
|
/clawsweeper re-review |
bff8142 to
d1a54ba
Compare
|
/clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
/clawsweeper re-review |
ae443fc to
0f3330f
Compare
|
/clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
/clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
/clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
/clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
/clawsweeper re-review |
1 similar comment
|
/clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
/clawsweeper re-review |
1 similar comment
|
/clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
/clawsweeper re-review |
3 similar comments
|
/clawsweeper re-review |
|
/clawsweeper re-review |
|
/clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
/clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
/clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
/clawsweeper re-review |
1 similar comment
|
/clawsweeper re-review |
|
Merged via squash.
|
What Problem This Solves
Signal users could receive a normal agent reply without the lifecycle status reactions already available in other message channels. When status reactions are configured, Signal can now show that an inbound message was acknowledged, is being processed, is using tools or compacting, has stalled, and then completed or failed.
Why This Change Was Made
Signal inbound handling now uses the shared status-reaction controller behind the existing
messages.statusReactions.enabled, acknowledgement scope, and SignalreactionLevelgates. Direct messages react to the inbound sender/timestamp; group messages react through the group id plus the original message author; reaction send/remove failures are logged without blocking the agent dispatch path.The shared dispatch path also forwards opted-in compaction lifecycle callbacks when normal progress text is hidden, so reaction-only progress can still move through compacting and back to thinking.
The observed
⏳hourglass is intentional. It is the shared soft-stall status (stallSoft) from the default status-reaction timing, and Signal also uses it as the default hard-stall reaction so a long-running turn does not look like a terminal failure. Explicit configuredmessages.statusReactions.emojis.stallHardoverrides are still honored.User Impact
Configured Signal routes can show live status reactions during an agent turn instead of only typing/read feedback. Replies that are sent through message tools are treated as successful visible replies, so the final status does not incorrectly flash as an error when the reply was delivered through that path.
Evidence
Manual Signal proof:
~/.openclawwas not touched.atlassian-ai-gateway/gpt-5.5-2026-04-23onhttp://127.0.0.1:19090/v1before the successful proof.heyin Testing realm. The visible lifecycle showed acknowledgement/thinking status, typing, the expected hourglass stall status, final status, and a delivered reply./v1/responsesreturning HTTP 200, Signal typing/reaction REST calls, and the final Signal/v2/sendreturning HTTP 201.⚠️only because the shared hard-stall lifecycle emoji was still Signal's default; Signal REST calls were 2xx and replies later delivered. This PR now maps Signal's default hard-stall reaction to the non-failure hourglass while preserving explicit configured hard-stall overrides.Reviewer-checkable proof:
origin/mainis one commit (d14071f2dfb) across Signal inbound runtime, shared dispatch callback gating, config schema/help, generated docs baseline, and focused tests.origin/mainand PR JSONL baselines with the same dependency tree had 0 added/removed API records, and noopenclaw/plugin-sdk/reply-runtimehelper export drift. The plugin SDK baseline hash was left unchanged.extensions/zalo,extensions/qa-lab,pnpm-lock.yaml, orpnpm-workspace.yamldiff; installed@openclaw/[email protected]excludeszalofromCRABLINE_SERVER_CHANNELSin its runtime/types while docs still mention Zalo.Automated checks:
git diff --checknode --import tsx scripts/generate-config-doc-baseline.ts --checknode --import tsx scripts/generate-base-config-schema.ts --checknode scripts/generate-docs-map.mjs --checknode_modules/.bin/oxfmt --check --threads=1 docs/channels/signal.md docs/gateway/config-agents.md extensions/signal/src/monitor/event-handler.ts extensions/signal/src/monitor/event-handler.inbound-context.test.ts src/auto-reply/reply/dispatch-from-config.ts src/auto-reply/reply/dispatch-from-config.test.ts src/config/schema.help.ts src/config/schema.test.ts src/config/types.messages.ts src/config/zod-schema.session.tsnode scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.extensions.json extensions/signal/src/monitor/event-handler.ts extensions/signal/src/monitor/event-handler.inbound-context.test.tsnode scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.core.json src/auto-reply/reply/dispatch-from-config.ts src/auto-reply/reply/dispatch-from-config.test.ts src/config/schema.help.ts src/config/schema.test.ts src/config/types.messages.ts src/config/zod-schema.session.tsnode scripts/run-tsgo.mjs -p tsconfig.extensions.jsonnode scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.jsonnode scripts/run-tsgo.mjs -p tsconfig.core.jsonnode scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.jsonOPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs extensions/signal/src/monitor/event-handler.inbound-context.test.ts src/auto-reply/reply/dispatch-from-config.test.ts src/config/schema.test.ts src/config/doc-baseline.integration.test.ts -- --reporter=verboseOPENCLAW_VITEST_MAX_WORKERS=1 /opt/homebrew/opt/node/bin/node scripts/run-vitest.mjs extensions/signal/src/monitor/event-handler.inbound-context.test.tspnpm docs:check-mdxpnpm format:docs:check