Skip to content

fix(message): strip auto-populated poll and components params on send#708

Open
BingqingLyu wants to merge 5 commits into
mainfrom
fork-pr-46455-fix-strip-poll-and-components-on-send
Open

fix(message): strip auto-populated poll and components params on send#708
BingqingLyu wants to merge 5 commits into
mainfrom
fork-pr-46455-fix-strip-poll-and-components-on-send

Conversation

@BingqingLyu

@BingqingLyu BingqingLyu commented Apr 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • Strip auto-populated poll creation parameters from action="send" requests before the poll guard check
  • Tighten hasPollCreationParams() to only gate on pollQuestion presence (the only field that unambiguously signals poll intent)
  • Strip empty/skeleton components objects that models auto-populate from the shared tool schema

Problem

Models (especially GPT-family) auto-fill optional poll and components fields from the message tool schema even when the user only wants a plain send. This causes:

  1. Poll guard false positive: hasPollCreationParams() returns true on default values like pollDurationHours: 0 (Number.isFinite(0) is true), rejecting valid send+attachment requests with Poll fields require action "poll".

  2. Empty components skeleton: auto-populated components.modal with empty fields: [] causes Discord rendering issues (broken attachment display, red X buttons) and validation errors.

Changes

File Change
src/poll-params.ts hasPollCreationParams() now only checks pollQuestion; added stripPollCreationParams()
src/infra/outbound/message-action-runner.ts Strip poll params on action="send" before guard; call stripEmptyComponents() after parsing
src/infra/outbound/message-action-params.ts Added stripEmptyComponents() to remove empty modal/blocks/text
src/poll-params.test.ts Updated tests for new gating logic + strip function coverage
src/infra/outbound/message-action-runner.context.test.ts Updated 3 tests: send+poll params now resolves instead of rejects

Test plan

  • src/poll-params.test.ts — 10 tests passed
  • src/infra/outbound/message-action-runner.poll.test.ts — 6 tests passed
  • src/infra/outbound/message-action-runner.context.test.ts — all passed
  • All 6 test files, 64 tests passed with zero failures
  • VPS live test: Discord image send via CLI succeeds (text+image, pure text, pure image)
  • VPS live test: Bot no longer throws "Poll fields require action poll" on send

Fixes openclaw#42820
Fixes openclaw#43015

0xsline added 5 commits March 15, 2026 01:42
Models (especially GPT-family) tend to auto-fill optional poll and
components fields from the shared message tool schema even when the user
only wants a plain send with text/attachments. This causes two distinct
failures:

1. Poll guard false positive: `hasPollCreationParams()` triggers on
   default values like `pollDurationHours: 0` (Number.isFinite(0) is
   true), rejecting valid send requests with "Poll fields require
   action poll".

2. Empty components skeleton: auto-populated `components.modal` with
   empty `fields: []` causes Discord rendering issues (broken attachment
   display, red X buttons) and validation errors.

Fix:
- `hasPollCreationParams()` now gates on `pollQuestion` only — without
  a question there is no actionable poll intent.
- New `stripPollCreationParams()` removes all poll params (camelCase
  and snake_case) from send requests before the guard check.
- New `stripEmptyComponents()` removes empty/skeleton components
  objects (no blocks, no text, empty modal) after parsing.

Fixes openclaw#42820
Fixes openclaw#43015
Addresses review feedback: move stripEmptyComponents() call after
action binding and scope it to send-only, so modal/broadcast/edit
actions are not affected by the cleanup.
The guard can never fire after stripPollCreationParams removes all poll
params. Remove the unreachable throw and unused hasPollCreationParams
import. Addresses Greptile review feedback.
…ents

- Skip stripping for array-based components (Discord TopLevelComponents[])
- Preserve container-only payloads (accentColor, reusable, spoiler)
- Only strip truly empty skeleton objects with no meaningful content

Addresses Codex P1 review feedback.
Keep the corrective error when pollQuestion is explicitly provided with
action=send — the caller likely meant action=poll. Only strip noise
params (pollDurationHours, pollMulti, etc.) that models auto-fill from
the shared schema without poll intent.

Addresses Codex P2 review feedback.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants