


















11// Parses poll command parameters into validated polling options.
2-import { parseStrictFiniteNumber } from "@openclaw/normalization-core/number-coercion";
3-import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce";
42import { readSnakeCaseParamRaw } from "./param-key.js";
5364type PollCreationParamKind = "string" | "stringArray" | "positiveInteger" | "boolean";
@@ -24,65 +22,17 @@ type SharedPollCreationParamName = keyof typeof SHARED_POLL_CREATION_PARAM_DEFS;
2422export const SHARED_POLL_CREATION_PARAM_NAMES = Object.keys(
2523SHARED_POLL_CREATION_PARAM_DEFS,
2624) as SharedPollCreationParamName[];
27-const SHARED_POLL_CREATION_PARAM_KEY_SET = new Set(
28-SHARED_POLL_CREATION_PARAM_NAMES.map(normalizePollParamKey),
29-);
30-const POLL_VOTE_PARAM_KEY_SET = new Set(
31-["pollId", "pollOptionId", "pollOptionIds", "pollOptionIndex", "pollOptionIndexes"].map(
32-normalizePollParamKey,
33-),
34-);
35253626function readPollParamRaw(params: Record<string, unknown>, key: string): unknown {
3727return readSnakeCaseParamRaw(params, key);
3828}
392940-function normalizePollParamKey(key: string): string {
41-return normalizeLowercaseStringOrEmpty(key.replaceAll("_", ""));
42-}
43-44-function isChannelPollCreationParamName(key: string): boolean {
45-const normalized = normalizePollParamKey(key);
46-return (
47-normalized.startsWith("poll") &&
48-!SHARED_POLL_CREATION_PARAM_KEY_SET.has(normalized) &&
49-!POLL_VOTE_PARAM_KEY_SET.has(normalized)
50-);
51-}
52-53-function hasExplicitUnknownPollValue(key: string, value: unknown): boolean {
54-if (value === true) {
55-return true;
56-}
57-if (typeof value === "number") {
58-return Number.isFinite(value) && value !== 0;
59-}
60-if (typeof value === "string") {
61-const trimmed = value.trim();
62-if (trimmed.length === 0) {
63-return false;
64-}
65-if (normalizePollParamKey(key).includes("duration")) {
66-const parsed = parseStrictFiniteNumber(trimmed);
67-return Number.isFinite(parsed) && parsed !== 0;
68-}
69-const normalized = normalizeLowercaseStringOrEmpty(trimmed);
70-return normalized !== "false" && normalized !== "0";
71-}
72-if (Array.isArray(value)) {
73-return value.some((entry) => hasExplicitUnknownPollValue(key, entry));
74-}
75-return false;
76-}
77-7830// Among the shared poll params, only the content-bearing fields (pollQuestion,
7931// pollOption) signal poll intent on their own. The modifier fields
80-// (pollDurationHours, pollMulti) are exposed by the shared `message` tool
81-// schema for both `send` and `poll` actions, so LLMs routinely echo their
82-// schema-implied defaults (`1`, `false`) on plain `send` calls — see issue
83-// for context. Treating those modifier defaults as "the agent meant to create
84-// a poll" produces false positives and blocks routine sends. The modifiers
85-// only count when accompanied by a content-bearing field.
32+// (pollDurationHours, pollMulti) and channel-specific metadata
33+// (pollDurationSeconds, pollPublic, pollAnonymous) are also exposed on the
34+// shared `message` tool schema, so schema-padded plain sends may echo them.
35+// Only content fields count here; action="poll" validates modifiers later.
8636const CONTENT_BEARING_SHARED_POLL_PARAM_NAMES = ["pollQuestion", "pollOption"] as const;
87378838function hasContentBearingPollCreationParam(params: Record<string, unknown>): boolean {
@@ -108,17 +58,5 @@ function hasContentBearingPollCreationParam(params: Record<string, unknown>): bo
10858}
1095911060export function hasPollCreationParams(params: Record<string, unknown>): boolean {
111-if (hasContentBearingPollCreationParam(params)) {
112-return true;
113-}
114-// Channel-specific poll-prefixed params (e.g. pollDurationSeconds,
115-// pollPublic) are not part of the shared schema, so an explicit value still
116-// indicates deliberate poll intent and continues to trigger the validator
117-// even without a pollQuestion/pollOption.
118-for (const [key, value] of Object.entries(params)) {
119-if (isChannelPollCreationParamName(key) && hasExplicitUnknownPollValue(key, value)) {
120-return true;
121-}
122-}
123-return false;
61+return hasContentBearingPollCreationParam(params);
12462}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。