Skip to content

fix(slack): guard against undefined text in includes calls during mention handling#31865

Merged
steipete merged 2 commits intoopenclaw:mainfrom
stone-jin:fix/slack-mention-includes-undefined
Mar 2, 2026
Merged

fix(slack): guard against undefined text in includes calls during mention handling#31865
steipete merged 2 commits intoopenclaw:mainfrom
stone-jin:fix/slack-mention-includes-undefined

Conversation

@stone-jin
Copy link
Contributor

Summary

  • Add defensive null/undefined guards to stripStructuralPrefixes in src/auto-reply/reply/mentions.ts and escapeSlackMrkdwnContent/escapeSlackMrkdwnText in src/slack/format.ts
  • These functions call .includes() on their text parameter without checking for undefined, causing Cannot read properties of undefined (reading 'includes') when the bot is @mentioned in Slack

Closes #31851

Changes

  • src/auto-reply/reply/mentions.ts: Add early return for falsy text in stripStructuralPrefixes
  • src/slack/format.ts: Add early return for falsy text in escapeSlackMrkdwnContent and escapeSlackMrkdwnText
  • src/auto-reply/reply/mentions.test.ts: New test file covering undefined/empty/normal inputs
  • src/slack/format.test.ts: Added test for undefined input to markdownToSlackMrkdwn

Test plan

  • Unit tests pass for undefined input scenarios
  • Existing tests continue to pass
  • Manual test: mention @bot in Slack channel — should respond without throwing

Made with Cursor

@openclaw-barnacle openclaw-barnacle bot added channel: slack Channel integration: slack size: XS labels Mar 2, 2026
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 2, 2026

Greptile Summary

This PR adds defensive null/undefined guards to three text-processing functions to prevent runtime errors when handling Slack mentions. The guards check for falsy text values before calling .includes(), returning empty strings instead of throwing errors.

  • Added early return guards to stripStructuralPrefixes, escapeSlackMrkdwnContent, and escapeSlackMrkdwnText
  • All three functions now return "" when given falsy input (undefined, null, or empty string)
  • Test coverage includes undefined and edge case scenarios
  • Fixes the "Cannot read properties of undefined (reading 'includes')" error when the bot is @mentioned in Slack

The implementation is clean and consistent - the guards are placed at the function entry points before any string methods are called, and the empty string return value aligns with the expected behavior for these formatting functions.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk - it adds defensive guards to prevent runtime errors without changing existing behavior
  • Score reflects straightforward defensive programming with good test coverage. The changes are minimal (3 guard clauses), focused on a specific issue (undefined text causing .includes() errors), and well-tested. The guards only affect error scenarios (undefined/null input) where the functions would have thrown anyway, so there's no risk of behavior change for valid inputs. All existing call sites already have fallbacks or valid strings, making this purely defensive.
  • No files require special attention - all changes are simple guard clauses with clear intent

Last reviewed commit: 0a9d299

@steipete steipete force-pushed the fix/slack-mention-includes-undefined branch from 0a9d299 to 9499957 Compare March 2, 2026 19:00
@steipete steipete merged commit c146748 into openclaw:main Mar 2, 2026
9 checks passed
@steipete
Copy link
Contributor

steipete commented Mar 2, 2026

Landed via temp rebase onto main.

  • Gate: \

openclaw@2026.3.2 test /Users/steipete/Projects/clawdbot5
node scripts/test-parallel.mjs src/auto-reply/reply/mentions.test.ts

RUN v4.0.18 /Users/steipete/Projects/clawdbot5

✓ src/auto-reply/reply/mentions.test.ts (4 tests) 2ms

Test Files 1 passed (1)
Tests 4 passed (4)
Start at 19:00:16
Duration 322ms (transform 203ms, setup 111ms, import 138ms, tests 2ms, environment 0ms)
\

openclaw@2026.3.2 test /Users/steipete/Projects/clawdbot5
node scripts/test-parallel.mjs src/slack/format.test.ts -t 'does not throw when input is undefined at runtime'

RUN v4.0.18 /Users/steipete/Projects/clawdbot5

✓ src/slack/format.test.ts (6 tests | 5 skipped) 3ms

Test Files 1 passed (1)
Tests 1 passed | 5 skipped (6)
Start at 19:00:17
Duration 252ms (transform 130ms, setup 108ms, import 66ms, tests 3ms, environment 0ms)

Thanks @stone-jin!
EOF && gh pr view 31865 --json state,mergedAt --jq '.state + " @ " + .mergedAt'

steipete added a commit to liuxiaopai-ai/openclaw that referenced this pull request Mar 2, 2026
steipete added a commit that referenced this pull request Mar 2, 2026
* fix(plugins): fallback install entrypoints for legacy manifests

* Voice Call: enforce exact webhook path match

* Tests: isolate webhook path suite and reset cron auth state

* chore: keep #31930 scoped to voice webhook path fix

* fix: add changelog for exact voice webhook path match (#31930) (thanks @afurm)

* fix: handle HTTP 529 (Anthropic overloaded) in failover error classification

Classify Anthropic's 529 status code as "rate_limit" so model fallback
triggers reliably without depending on fragile message-based detection.

Closes #28502

* fix: add changelog for HTTP 529 failover classification (#31854) (thanks @bugkill3r)

* fix(slack): guard against undefined text in includes calls during mention handling

* fix: add changelog for mentions/slack null-safe guards (#31865) (thanks @stone-jin)

* fix(memory-lancedb): pass dimensions to embedding API call

- Add dimensions parameter to Embeddings constructor
- Pass dimensions to OpenAI embeddings.create() API call
- Fixes dimension mismatch when using custom embedding models like DashScope text-embedding-v4

* fix: add regression for memory-lancedb dimensions pass-through (#32036) (thanks @scotthuang)

* fix(telegram): guard malformed native menu specs

* fix: harden plugin command registration + telegram menu guard (#31997) (thanks @liuxiaopai-ai)

* fix(gateway): restart heartbeat on model config changes

* fix: add changelog credit for heartbeat model reload (#32046) (thanks @stakeswky)

* test(process): replace no-output timer subprocess with spawn mock

* test(perf): trim repeated setup in cron memory and config suites

* test(perf): reduce per-case setup in script and git-hook tests

* fix(slack): scope debounce key by message timestamp to prevent cross-thread collisions

Top-level channel messages from the same sender shared a bare channel
debounce key, causing concurrent messages in different threads to merge
into a single reply on the wrong thread. Now the debounce key includes
the message timestamp for top-level messages, matching how the downstream
session layer already scopes by canonicalThreadId.

Extracted buildSlackDebounceKey() for testability.

Closes #31935

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: harden slack debounce key routing and ordering (#31951) (thanks @scoootscooob)

* fix(openrouter): skip reasoning.effort injection for x-ai/grok models

x-ai/grok models on OpenRouter do not support the reasoning.effort
parameter and reject payloads containing it with "Invalid arguments
passed to the model." Skip reasoning injection for these models, the
same way we already skip it for the dynamic "auto" routing model.

Closes #32039

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add changelog credit for openrouter x-ai reasoning guard (#32054) (thanks @scoootscooob)

* fix(agents): scope volcengine-plan/byteplus-plan auth lookup to profile resolution

The configure flow stores auth credentials under `provider: "volcengine"`,
but the coding model uses `volcengine-plan` as its provider. Add a scoped
`normalizeProviderIdForAuth` function used only by `listProfilesForProvider`
so coding-plan variants resolve to their base provider for auth credential
lookup without affecting global provider routing.

Closes #31731

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(tools): honor fsPolicy.workspaceOnly in image/pdf tool localRoots

PR #28822 fixed the Write/Edit tools to respect `tools.fs.workspaceOnly`,
but the image and PDF tools still unconditionally include default local
roots (`~/.openclaw/media`, `~/.openclaw/agents`, etc.) when computing
the `localRoots` allowlist for non-sandbox mode.

When `fsPolicy.workspaceOnly` is true, restrict `localRoots` to only the
workspace directory so that files outside the workspace are rejected by
`assertLocalMediaAllowed()`.

Relates to #31716

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add changelog credit for fsPolicy image/pdf propagation (#31882) (thanks @justinhuangcode)

* fix: skip Telegram command sync when menu is unchanged (#32017)

Hash the command list and cache it to disk per account. On restart,
compare the current hash against the cached one and skip the
deleteMyCommands + setMyCommands round-trip when nothing changed.
This prevents 429 rate-limit errors when the gateway restarts
several times in quick succession.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(telegram): scope command-sync hash cache by bot identity (#32059)

* fix: normalize coding-plan providers in auth order validation

* feat(security): Harden Docker browser container chromium flags (#23889) (#31504)

* Gateway: honor OPENCLAW_GATEWAY_URL override for remote/local calls

* Agents: fix sandbox sessionKey usage for PI embedded subagent calls

* Sandbox: tighten browser container Chromium runtime flags

* fix: add sandbox browser defaults for container hardening

* docs: expand sandbox browser default flags list

* fix: make sandbox browser flags optional and preserve gateway env auth overrides

* docs: scope PR 31504 changelog entry

* style: format gateway call override handling

* fix: dedupe sandbox browser chrome args

* fix: preserve remote tls fingerprint for env gateway override

* fix: enforce auth for env gateway URL override

* chore: document gateway override auth security expectations

* fix(delivery): strip HTML tags for plain-text messaging surfaces

Models occasionally produce HTML tags in their output. While these render
fine on web surfaces, they appear as literal text on WhatsApp, Signal,
SMS, IRC, and Telegram.

Add sanitizeForPlainText() utility that converts common inline HTML to
lightweight-markup equivalents and strips remaining tags. Applied in the
outbound delivery pipeline for non-HTML surfaces only.

Closes #31884
See also: #18558

* fix(outbound): harden plain-text HTML sanitization paths (#32034)

* fix(security): harden file installs and race-path tests

* matrix: bootstrap crypto runtime when npm scripts are skipped

* fix(matrix): keep plugin register sync while bootstrapping crypto runtime (#31989)

* perf(runtime): reduce cron persistence and logger overhead

* test(perf): use prebuilt plugin install archive fixtures

* test(perf): increase guardrail scan read concurrency

* fix(queue): restart drain when message enqueued after idle window

After a drain loop empties the queue it deletes the key from
FOLLOWUP_QUEUES.  If a new message arrives at that moment
enqueueFollowupRun creates a fresh queue object with draining:false
but never starts a drain, leaving the message stranded until the
next run completes and calls finalizeWithFollowup.

Fix: persist the most recent runFollowup callback per queue key in
FOLLOWUP_RUN_CALLBACKS (drain.ts).  enqueueFollowupRun now calls
kickFollowupDrainIfIdle after a successful push; if a cached
callback exists and no drain is running it calls scheduleFollowupDrain
to restart immediately.  clearSessionQueues cleans up the callback
cache alongside the queue state.

* fix: avoid stale followup drain callbacks (#31902) (thanks @Lanfei)

* fix(synology-chat): read cfg from outbound context so incomingUrl resolves

* fix: require openclaw.extensions for plugin installs (#32055) (thanks @liuxiaopai-ai)

---------

Co-authored-by: Andrii Furmanets <furmanets.andriy@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Saurabh <skmishra1991@gmail.com>
Co-authored-by: stone-jin <1520006273@qq.com>
Co-authored-by: scotthuang <scotthuang@tencent.com>
Co-authored-by: User <user@example.com>
Co-authored-by: scoootscooob <zhentongfan@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: justinhuangcode <justinhuangcode@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: AytuncYildizli <cryptosquanch@gmail.com>
Co-authored-by: bmendonca3 <bmendonca3@users.noreply.github.com>
Co-authored-by: Jealous <CooLanfei@163.com>
Co-authored-by: white-rm <zhang.xujin@xydigit.com>
execute008 pushed a commit to execute008/openclaw that referenced this pull request Mar 2, 2026
execute008 pushed a commit to execute008/openclaw that referenced this pull request Mar 2, 2026
* fix(plugins): fallback install entrypoints for legacy manifests

* Voice Call: enforce exact webhook path match

* Tests: isolate webhook path suite and reset cron auth state

* chore: keep openclaw#31930 scoped to voice webhook path fix

* fix: add changelog for exact voice webhook path match (openclaw#31930) (thanks @afurm)

* fix: handle HTTP 529 (Anthropic overloaded) in failover error classification

Classify Anthropic's 529 status code as "rate_limit" so model fallback
triggers reliably without depending on fragile message-based detection.

Closes openclaw#28502

* fix: add changelog for HTTP 529 failover classification (openclaw#31854) (thanks @bugkill3r)

* fix(slack): guard against undefined text in includes calls during mention handling

* fix: add changelog for mentions/slack null-safe guards (openclaw#31865) (thanks @stone-jin)

* fix(memory-lancedb): pass dimensions to embedding API call

- Add dimensions parameter to Embeddings constructor
- Pass dimensions to OpenAI embeddings.create() API call
- Fixes dimension mismatch when using custom embedding models like DashScope text-embedding-v4

* fix: add regression for memory-lancedb dimensions pass-through (openclaw#32036) (thanks @scotthuang)

* fix(telegram): guard malformed native menu specs

* fix: harden plugin command registration + telegram menu guard (openclaw#31997) (thanks @liuxiaopai-ai)

* fix(gateway): restart heartbeat on model config changes

* fix: add changelog credit for heartbeat model reload (openclaw#32046) (thanks @stakeswky)

* test(process): replace no-output timer subprocess with spawn mock

* test(perf): trim repeated setup in cron memory and config suites

* test(perf): reduce per-case setup in script and git-hook tests

* fix(slack): scope debounce key by message timestamp to prevent cross-thread collisions

Top-level channel messages from the same sender shared a bare channel
debounce key, causing concurrent messages in different threads to merge
into a single reply on the wrong thread. Now the debounce key includes
the message timestamp for top-level messages, matching how the downstream
session layer already scopes by canonicalThreadId.

Extracted buildSlackDebounceKey() for testability.

Closes openclaw#31935

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: harden slack debounce key routing and ordering (openclaw#31951) (thanks @scoootscooob)

* fix(openrouter): skip reasoning.effort injection for x-ai/grok models

x-ai/grok models on OpenRouter do not support the reasoning.effort
parameter and reject payloads containing it with "Invalid arguments
passed to the model." Skip reasoning injection for these models, the
same way we already skip it for the dynamic "auto" routing model.

Closes openclaw#32039

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add changelog credit for openrouter x-ai reasoning guard (openclaw#32054) (thanks @scoootscooob)

* fix(agents): scope volcengine-plan/byteplus-plan auth lookup to profile resolution

The configure flow stores auth credentials under `provider: "volcengine"`,
but the coding model uses `volcengine-plan` as its provider. Add a scoped
`normalizeProviderIdForAuth` function used only by `listProfilesForProvider`
so coding-plan variants resolve to their base provider for auth credential
lookup without affecting global provider routing.

Closes openclaw#31731

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(tools): honor fsPolicy.workspaceOnly in image/pdf tool localRoots

PR openclaw#28822 fixed the Write/Edit tools to respect `tools.fs.workspaceOnly`,
but the image and PDF tools still unconditionally include default local
roots (`~/.openclaw/media`, `~/.openclaw/agents`, etc.) when computing
the `localRoots` allowlist for non-sandbox mode.

When `fsPolicy.workspaceOnly` is true, restrict `localRoots` to only the
workspace directory so that files outside the workspace are rejected by
`assertLocalMediaAllowed()`.

Relates to openclaw#31716

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add changelog credit for fsPolicy image/pdf propagation (openclaw#31882) (thanks @justinhuangcode)

* fix: skip Telegram command sync when menu is unchanged (openclaw#32017)

Hash the command list and cache it to disk per account. On restart,
compare the current hash against the cached one and skip the
deleteMyCommands + setMyCommands round-trip when nothing changed.
This prevents 429 rate-limit errors when the gateway restarts
several times in quick succession.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(telegram): scope command-sync hash cache by bot identity (openclaw#32059)

* fix: normalize coding-plan providers in auth order validation

* feat(security): Harden Docker browser container chromium flags (openclaw#23889) (openclaw#31504)

* Gateway: honor OPENCLAW_GATEWAY_URL override for remote/local calls

* Agents: fix sandbox sessionKey usage for PI embedded subagent calls

* Sandbox: tighten browser container Chromium runtime flags

* fix: add sandbox browser defaults for container hardening

* docs: expand sandbox browser default flags list

* fix: make sandbox browser flags optional and preserve gateway env auth overrides

* docs: scope PR 31504 changelog entry

* style: format gateway call override handling

* fix: dedupe sandbox browser chrome args

* fix: preserve remote tls fingerprint for env gateway override

* fix: enforce auth for env gateway URL override

* chore: document gateway override auth security expectations

* fix(delivery): strip HTML tags for plain-text messaging surfaces

Models occasionally produce HTML tags in their output. While these render
fine on web surfaces, they appear as literal text on WhatsApp, Signal,
SMS, IRC, and Telegram.

Add sanitizeForPlainText() utility that converts common inline HTML to
lightweight-markup equivalents and strips remaining tags. Applied in the
outbound delivery pipeline for non-HTML surfaces only.

Closes openclaw#31884
See also: openclaw#18558

* fix(outbound): harden plain-text HTML sanitization paths (openclaw#32034)

* fix(security): harden file installs and race-path tests

* matrix: bootstrap crypto runtime when npm scripts are skipped

* fix(matrix): keep plugin register sync while bootstrapping crypto runtime (openclaw#31989)

* perf(runtime): reduce cron persistence and logger overhead

* test(perf): use prebuilt plugin install archive fixtures

* test(perf): increase guardrail scan read concurrency

* fix(queue): restart drain when message enqueued after idle window

After a drain loop empties the queue it deletes the key from
FOLLOWUP_QUEUES.  If a new message arrives at that moment
enqueueFollowupRun creates a fresh queue object with draining:false
but never starts a drain, leaving the message stranded until the
next run completes and calls finalizeWithFollowup.

Fix: persist the most recent runFollowup callback per queue key in
FOLLOWUP_RUN_CALLBACKS (drain.ts).  enqueueFollowupRun now calls
kickFollowupDrainIfIdle after a successful push; if a cached
callback exists and no drain is running it calls scheduleFollowupDrain
to restart immediately.  clearSessionQueues cleans up the callback
cache alongside the queue state.

* fix: avoid stale followup drain callbacks (openclaw#31902) (thanks @Lanfei)

* fix(synology-chat): read cfg from outbound context so incomingUrl resolves

* fix: require openclaw.extensions for plugin installs (openclaw#32055) (thanks @liuxiaopai-ai)

---------

Co-authored-by: Andrii Furmanets <furmanets.andriy@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Saurabh <skmishra1991@gmail.com>
Co-authored-by: stone-jin <1520006273@qq.com>
Co-authored-by: scotthuang <scotthuang@tencent.com>
Co-authored-by: User <user@example.com>
Co-authored-by: scoootscooob <zhentongfan@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: justinhuangcode <justinhuangcode@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: AytuncYildizli <cryptosquanch@gmail.com>
Co-authored-by: bmendonca3 <bmendonca3@users.noreply.github.com>
Co-authored-by: Jealous <CooLanfei@163.com>
Co-authored-by: white-rm <zhang.xujin@xydigit.com>
dawi369 pushed a commit to dawi369/davis that referenced this pull request Mar 3, 2026
dawi369 pushed a commit to dawi369/davis that referenced this pull request Mar 3, 2026
* fix(plugins): fallback install entrypoints for legacy manifests

* Voice Call: enforce exact webhook path match

* Tests: isolate webhook path suite and reset cron auth state

* chore: keep openclaw#31930 scoped to voice webhook path fix

* fix: add changelog for exact voice webhook path match (openclaw#31930) (thanks @afurm)

* fix: handle HTTP 529 (Anthropic overloaded) in failover error classification

Classify Anthropic's 529 status code as "rate_limit" so model fallback
triggers reliably without depending on fragile message-based detection.

Closes openclaw#28502

* fix: add changelog for HTTP 529 failover classification (openclaw#31854) (thanks @bugkill3r)

* fix(slack): guard against undefined text in includes calls during mention handling

* fix: add changelog for mentions/slack null-safe guards (openclaw#31865) (thanks @stone-jin)

* fix(memory-lancedb): pass dimensions to embedding API call

- Add dimensions parameter to Embeddings constructor
- Pass dimensions to OpenAI embeddings.create() API call
- Fixes dimension mismatch when using custom embedding models like DashScope text-embedding-v4

* fix: add regression for memory-lancedb dimensions pass-through (openclaw#32036) (thanks @scotthuang)

* fix(telegram): guard malformed native menu specs

* fix: harden plugin command registration + telegram menu guard (openclaw#31997) (thanks @liuxiaopai-ai)

* fix(gateway): restart heartbeat on model config changes

* fix: add changelog credit for heartbeat model reload (openclaw#32046) (thanks @stakeswky)

* test(process): replace no-output timer subprocess with spawn mock

* test(perf): trim repeated setup in cron memory and config suites

* test(perf): reduce per-case setup in script and git-hook tests

* fix(slack): scope debounce key by message timestamp to prevent cross-thread collisions

Top-level channel messages from the same sender shared a bare channel
debounce key, causing concurrent messages in different threads to merge
into a single reply on the wrong thread. Now the debounce key includes
the message timestamp for top-level messages, matching how the downstream
session layer already scopes by canonicalThreadId.

Extracted buildSlackDebounceKey() for testability.

Closes openclaw#31935

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: harden slack debounce key routing and ordering (openclaw#31951) (thanks @scoootscooob)

* fix(openrouter): skip reasoning.effort injection for x-ai/grok models

x-ai/grok models on OpenRouter do not support the reasoning.effort
parameter and reject payloads containing it with "Invalid arguments
passed to the model." Skip reasoning injection for these models, the
same way we already skip it for the dynamic "auto" routing model.

Closes openclaw#32039

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add changelog credit for openrouter x-ai reasoning guard (openclaw#32054) (thanks @scoootscooob)

* fix(agents): scope volcengine-plan/byteplus-plan auth lookup to profile resolution

The configure flow stores auth credentials under `provider: "volcengine"`,
but the coding model uses `volcengine-plan` as its provider. Add a scoped
`normalizeProviderIdForAuth` function used only by `listProfilesForProvider`
so coding-plan variants resolve to their base provider for auth credential
lookup without affecting global provider routing.

Closes openclaw#31731

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(tools): honor fsPolicy.workspaceOnly in image/pdf tool localRoots

PR openclaw#28822 fixed the Write/Edit tools to respect `tools.fs.workspaceOnly`,
but the image and PDF tools still unconditionally include default local
roots (`~/.openclaw/media`, `~/.openclaw/agents`, etc.) when computing
the `localRoots` allowlist for non-sandbox mode.

When `fsPolicy.workspaceOnly` is true, restrict `localRoots` to only the
workspace directory so that files outside the workspace are rejected by
`assertLocalMediaAllowed()`.

Relates to openclaw#31716

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add changelog credit for fsPolicy image/pdf propagation (openclaw#31882) (thanks @justinhuangcode)

* fix: skip Telegram command sync when menu is unchanged (openclaw#32017)

Hash the command list and cache it to disk per account. On restart,
compare the current hash against the cached one and skip the
deleteMyCommands + setMyCommands round-trip when nothing changed.
This prevents 429 rate-limit errors when the gateway restarts
several times in quick succession.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(telegram): scope command-sync hash cache by bot identity (openclaw#32059)

* fix: normalize coding-plan providers in auth order validation

* feat(security): Harden Docker browser container chromium flags (openclaw#23889) (openclaw#31504)

* Gateway: honor OPENCLAW_GATEWAY_URL override for remote/local calls

* Agents: fix sandbox sessionKey usage for PI embedded subagent calls

* Sandbox: tighten browser container Chromium runtime flags

* fix: add sandbox browser defaults for container hardening

* docs: expand sandbox browser default flags list

* fix: make sandbox browser flags optional and preserve gateway env auth overrides

* docs: scope PR 31504 changelog entry

* style: format gateway call override handling

* fix: dedupe sandbox browser chrome args

* fix: preserve remote tls fingerprint for env gateway override

* fix: enforce auth for env gateway URL override

* chore: document gateway override auth security expectations

* fix(delivery): strip HTML tags for plain-text messaging surfaces

Models occasionally produce HTML tags in their output. While these render
fine on web surfaces, they appear as literal text on WhatsApp, Signal,
SMS, IRC, and Telegram.

Add sanitizeForPlainText() utility that converts common inline HTML to
lightweight-markup equivalents and strips remaining tags. Applied in the
outbound delivery pipeline for non-HTML surfaces only.

Closes openclaw#31884
See also: openclaw#18558

* fix(outbound): harden plain-text HTML sanitization paths (openclaw#32034)

* fix(security): harden file installs and race-path tests

* matrix: bootstrap crypto runtime when npm scripts are skipped

* fix(matrix): keep plugin register sync while bootstrapping crypto runtime (openclaw#31989)

* perf(runtime): reduce cron persistence and logger overhead

* test(perf): use prebuilt plugin install archive fixtures

* test(perf): increase guardrail scan read concurrency

* fix(queue): restart drain when message enqueued after idle window

After a drain loop empties the queue it deletes the key from
FOLLOWUP_QUEUES.  If a new message arrives at that moment
enqueueFollowupRun creates a fresh queue object with draining:false
but never starts a drain, leaving the message stranded until the
next run completes and calls finalizeWithFollowup.

Fix: persist the most recent runFollowup callback per queue key in
FOLLOWUP_RUN_CALLBACKS (drain.ts).  enqueueFollowupRun now calls
kickFollowupDrainIfIdle after a successful push; if a cached
callback exists and no drain is running it calls scheduleFollowupDrain
to restart immediately.  clearSessionQueues cleans up the callback
cache alongside the queue state.

* fix: avoid stale followup drain callbacks (openclaw#31902) (thanks @Lanfei)

* fix(synology-chat): read cfg from outbound context so incomingUrl resolves

* fix: require openclaw.extensions for plugin installs (openclaw#32055) (thanks @liuxiaopai-ai)

---------

Co-authored-by: Andrii Furmanets <furmanets.andriy@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Saurabh <skmishra1991@gmail.com>
Co-authored-by: stone-jin <1520006273@qq.com>
Co-authored-by: scotthuang <scotthuang@tencent.com>
Co-authored-by: User <user@example.com>
Co-authored-by: scoootscooob <zhentongfan@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: justinhuangcode <justinhuangcode@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: AytuncYildizli <cryptosquanch@gmail.com>
Co-authored-by: bmendonca3 <bmendonca3@users.noreply.github.com>
Co-authored-by: Jealous <CooLanfei@163.com>
Co-authored-by: white-rm <zhang.xujin@xydigit.com>
OWALabuy pushed a commit to kcinzgg/openclaw that referenced this pull request Mar 4, 2026
OWALabuy pushed a commit to kcinzgg/openclaw that referenced this pull request Mar 4, 2026
* fix(plugins): fallback install entrypoints for legacy manifests

* Voice Call: enforce exact webhook path match

* Tests: isolate webhook path suite and reset cron auth state

* chore: keep openclaw#31930 scoped to voice webhook path fix

* fix: add changelog for exact voice webhook path match (openclaw#31930) (thanks @afurm)

* fix: handle HTTP 529 (Anthropic overloaded) in failover error classification

Classify Anthropic's 529 status code as "rate_limit" so model fallback
triggers reliably without depending on fragile message-based detection.

Closes openclaw#28502

* fix: add changelog for HTTP 529 failover classification (openclaw#31854) (thanks @bugkill3r)

* fix(slack): guard against undefined text in includes calls during mention handling

* fix: add changelog for mentions/slack null-safe guards (openclaw#31865) (thanks @stone-jin)

* fix(memory-lancedb): pass dimensions to embedding API call

- Add dimensions parameter to Embeddings constructor
- Pass dimensions to OpenAI embeddings.create() API call
- Fixes dimension mismatch when using custom embedding models like DashScope text-embedding-v4

* fix: add regression for memory-lancedb dimensions pass-through (openclaw#32036) (thanks @scotthuang)

* fix(telegram): guard malformed native menu specs

* fix: harden plugin command registration + telegram menu guard (openclaw#31997) (thanks @liuxiaopai-ai)

* fix(gateway): restart heartbeat on model config changes

* fix: add changelog credit for heartbeat model reload (openclaw#32046) (thanks @stakeswky)

* test(process): replace no-output timer subprocess with spawn mock

* test(perf): trim repeated setup in cron memory and config suites

* test(perf): reduce per-case setup in script and git-hook tests

* fix(slack): scope debounce key by message timestamp to prevent cross-thread collisions

Top-level channel messages from the same sender shared a bare channel
debounce key, causing concurrent messages in different threads to merge
into a single reply on the wrong thread. Now the debounce key includes
the message timestamp for top-level messages, matching how the downstream
session layer already scopes by canonicalThreadId.

Extracted buildSlackDebounceKey() for testability.

Closes openclaw#31935

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: harden slack debounce key routing and ordering (openclaw#31951) (thanks @scoootscooob)

* fix(openrouter): skip reasoning.effort injection for x-ai/grok models

x-ai/grok models on OpenRouter do not support the reasoning.effort
parameter and reject payloads containing it with "Invalid arguments
passed to the model." Skip reasoning injection for these models, the
same way we already skip it for the dynamic "auto" routing model.

Closes openclaw#32039

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add changelog credit for openrouter x-ai reasoning guard (openclaw#32054) (thanks @scoootscooob)

* fix(agents): scope volcengine-plan/byteplus-plan auth lookup to profile resolution

The configure flow stores auth credentials under `provider: "volcengine"`,
but the coding model uses `volcengine-plan` as its provider. Add a scoped
`normalizeProviderIdForAuth` function used only by `listProfilesForProvider`
so coding-plan variants resolve to their base provider for auth credential
lookup without affecting global provider routing.

Closes openclaw#31731

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(tools): honor fsPolicy.workspaceOnly in image/pdf tool localRoots

PR openclaw#28822 fixed the Write/Edit tools to respect `tools.fs.workspaceOnly`,
but the image and PDF tools still unconditionally include default local
roots (`~/.openclaw/media`, `~/.openclaw/agents`, etc.) when computing
the `localRoots` allowlist for non-sandbox mode.

When `fsPolicy.workspaceOnly` is true, restrict `localRoots` to only the
workspace directory so that files outside the workspace are rejected by
`assertLocalMediaAllowed()`.

Relates to openclaw#31716

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add changelog credit for fsPolicy image/pdf propagation (openclaw#31882) (thanks @justinhuangcode)

* fix: skip Telegram command sync when menu is unchanged (openclaw#32017)

Hash the command list and cache it to disk per account. On restart,
compare the current hash against the cached one and skip the
deleteMyCommands + setMyCommands round-trip when nothing changed.
This prevents 429 rate-limit errors when the gateway restarts
several times in quick succession.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(telegram): scope command-sync hash cache by bot identity (openclaw#32059)

* fix: normalize coding-plan providers in auth order validation

* feat(security): Harden Docker browser container chromium flags (openclaw#23889) (openclaw#31504)

* Gateway: honor OPENCLAW_GATEWAY_URL override for remote/local calls

* Agents: fix sandbox sessionKey usage for PI embedded subagent calls

* Sandbox: tighten browser container Chromium runtime flags

* fix: add sandbox browser defaults for container hardening

* docs: expand sandbox browser default flags list

* fix: make sandbox browser flags optional and preserve gateway env auth overrides

* docs: scope PR 31504 changelog entry

* style: format gateway call override handling

* fix: dedupe sandbox browser chrome args

* fix: preserve remote tls fingerprint for env gateway override

* fix: enforce auth for env gateway URL override

* chore: document gateway override auth security expectations

* fix(delivery): strip HTML tags for plain-text messaging surfaces

Models occasionally produce HTML tags in their output. While these render
fine on web surfaces, they appear as literal text on WhatsApp, Signal,
SMS, IRC, and Telegram.

Add sanitizeForPlainText() utility that converts common inline HTML to
lightweight-markup equivalents and strips remaining tags. Applied in the
outbound delivery pipeline for non-HTML surfaces only.

Closes openclaw#31884
See also: openclaw#18558

* fix(outbound): harden plain-text HTML sanitization paths (openclaw#32034)

* fix(security): harden file installs and race-path tests

* matrix: bootstrap crypto runtime when npm scripts are skipped

* fix(matrix): keep plugin register sync while bootstrapping crypto runtime (openclaw#31989)

* perf(runtime): reduce cron persistence and logger overhead

* test(perf): use prebuilt plugin install archive fixtures

* test(perf): increase guardrail scan read concurrency

* fix(queue): restart drain when message enqueued after idle window

After a drain loop empties the queue it deletes the key from
FOLLOWUP_QUEUES.  If a new message arrives at that moment
enqueueFollowupRun creates a fresh queue object with draining:false
but never starts a drain, leaving the message stranded until the
next run completes and calls finalizeWithFollowup.

Fix: persist the most recent runFollowup callback per queue key in
FOLLOWUP_RUN_CALLBACKS (drain.ts).  enqueueFollowupRun now calls
kickFollowupDrainIfIdle after a successful push; if a cached
callback exists and no drain is running it calls scheduleFollowupDrain
to restart immediately.  clearSessionQueues cleans up the callback
cache alongside the queue state.

* fix: avoid stale followup drain callbacks (openclaw#31902) (thanks @Lanfei)

* fix(synology-chat): read cfg from outbound context so incomingUrl resolves

* fix: require openclaw.extensions for plugin installs (openclaw#32055) (thanks @liuxiaopai-ai)

---------

Co-authored-by: Andrii Furmanets <furmanets.andriy@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Saurabh <skmishra1991@gmail.com>
Co-authored-by: stone-jin <1520006273@qq.com>
Co-authored-by: scotthuang <scotthuang@tencent.com>
Co-authored-by: User <user@example.com>
Co-authored-by: scoootscooob <zhentongfan@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: justinhuangcode <justinhuangcode@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: AytuncYildizli <cryptosquanch@gmail.com>
Co-authored-by: bmendonca3 <bmendonca3@users.noreply.github.com>
Co-authored-by: Jealous <CooLanfei@163.com>
Co-authored-by: white-rm <zhang.xujin@xydigit.com>
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
* fix(plugins): fallback install entrypoints for legacy manifests

* Voice Call: enforce exact webhook path match

* Tests: isolate webhook path suite and reset cron auth state

* chore: keep openclaw#31930 scoped to voice webhook path fix

* fix: add changelog for exact voice webhook path match (openclaw#31930) (thanks @afurm)

* fix: handle HTTP 529 (Anthropic overloaded) in failover error classification

Classify Anthropic's 529 status code as "rate_limit" so model fallback
triggers reliably without depending on fragile message-based detection.

Closes openclaw#28502

* fix: add changelog for HTTP 529 failover classification (openclaw#31854) (thanks @bugkill3r)

* fix(slack): guard against undefined text in includes calls during mention handling

* fix: add changelog for mentions/slack null-safe guards (openclaw#31865) (thanks @stone-jin)

* fix(memory-lancedb): pass dimensions to embedding API call

- Add dimensions parameter to Embeddings constructor
- Pass dimensions to OpenAI embeddings.create() API call
- Fixes dimension mismatch when using custom embedding models like DashScope text-embedding-v4

* fix: add regression for memory-lancedb dimensions pass-through (openclaw#32036) (thanks @scotthuang)

* fix(telegram): guard malformed native menu specs

* fix: harden plugin command registration + telegram menu guard (openclaw#31997) (thanks @liuxiaopai-ai)

* fix(gateway): restart heartbeat on model config changes

* fix: add changelog credit for heartbeat model reload (openclaw#32046) (thanks @stakeswky)

* test(process): replace no-output timer subprocess with spawn mock

* test(perf): trim repeated setup in cron memory and config suites

* test(perf): reduce per-case setup in script and git-hook tests

* fix(slack): scope debounce key by message timestamp to prevent cross-thread collisions

Top-level channel messages from the same sender shared a bare channel
debounce key, causing concurrent messages in different threads to merge
into a single reply on the wrong thread. Now the debounce key includes
the message timestamp for top-level messages, matching how the downstream
session layer already scopes by canonicalThreadId.

Extracted buildSlackDebounceKey() for testability.

Closes openclaw#31935


* fix: harden slack debounce key routing and ordering (openclaw#31951) (thanks @scoootscooob)

* fix(openrouter): skip reasoning.effort injection for x-ai/grok models

x-ai/grok models on OpenRouter do not support the reasoning.effort
parameter and reject payloads containing it with "Invalid arguments
passed to the model." Skip reasoning injection for these models, the
same way we already skip it for the dynamic "auto" routing model.

Closes openclaw#32039


* fix: add changelog credit for openrouter x-ai reasoning guard (openclaw#32054) (thanks @scoootscooob)

* fix(agents): scope volcengine-plan/byteplus-plan auth lookup to profile resolution

The configure flow stores auth credentials under `provider: "volcengine"`,
but the coding model uses `volcengine-plan` as its provider. Add a scoped
`normalizeProviderIdForAuth` function used only by `listProfilesForProvider`
so coding-plan variants resolve to their base provider for auth credential
lookup without affecting global provider routing.

Closes openclaw#31731


* fix(tools): honor fsPolicy.workspaceOnly in image/pdf tool localRoots

PR openclaw#28822 fixed the Write/Edit tools to respect `tools.fs.workspaceOnly`,
but the image and PDF tools still unconditionally include default local
roots (`~/.openclaw/media`, `~/.openclaw/agents`, etc.) when computing
the `localRoots` allowlist for non-sandbox mode.

When `fsPolicy.workspaceOnly` is true, restrict `localRoots` to only the
workspace directory so that files outside the workspace are rejected by
`assertLocalMediaAllowed()`.

Relates to openclaw#31716


* fix: add changelog credit for fsPolicy image/pdf propagation (openclaw#31882) (thanks @justinhuangcode)

* fix: skip Telegram command sync when menu is unchanged (openclaw#32017)

Hash the command list and cache it to disk per account. On restart,
compare the current hash against the cached one and skip the
deleteMyCommands + setMyCommands round-trip when nothing changed.
This prevents 429 rate-limit errors when the gateway restarts
several times in quick succession.


* fix(telegram): scope command-sync hash cache by bot identity (openclaw#32059)

* fix: normalize coding-plan providers in auth order validation

* feat(security): Harden Docker browser container chromium flags (openclaw#23889) (openclaw#31504)

* Gateway: honor OPENCLAW_GATEWAY_URL override for remote/local calls

* Agents: fix sandbox sessionKey usage for PI embedded subagent calls

* Sandbox: tighten browser container Chromium runtime flags

* fix: add sandbox browser defaults for container hardening

* docs: expand sandbox browser default flags list

* fix: make sandbox browser flags optional and preserve gateway env auth overrides

* docs: scope PR 31504 changelog entry

* style: format gateway call override handling

* fix: dedupe sandbox browser chrome args

* fix: preserve remote tls fingerprint for env gateway override

* fix: enforce auth for env gateway URL override

* chore: document gateway override auth security expectations

* fix(delivery): strip HTML tags for plain-text messaging surfaces

Models occasionally produce HTML tags in their output. While these render
fine on web surfaces, they appear as literal text on WhatsApp, Signal,
SMS, IRC, and Telegram.

Add sanitizeForPlainText() utility that converts common inline HTML to
lightweight-markup equivalents and strips remaining tags. Applied in the
outbound delivery pipeline for non-HTML surfaces only.

Closes openclaw#31884
See also: openclaw#18558

* fix(outbound): harden plain-text HTML sanitization paths (openclaw#32034)

* fix(security): harden file installs and race-path tests

* matrix: bootstrap crypto runtime when npm scripts are skipped

* fix(matrix): keep plugin register sync while bootstrapping crypto runtime (openclaw#31989)

* perf(runtime): reduce cron persistence and logger overhead

* test(perf): use prebuilt plugin install archive fixtures

* test(perf): increase guardrail scan read concurrency

* fix(queue): restart drain when message enqueued after idle window

After a drain loop empties the queue it deletes the key from
FOLLOWUP_QUEUES.  If a new message arrives at that moment
enqueueFollowupRun creates a fresh queue object with draining:false
but never starts a drain, leaving the message stranded until the
next run completes and calls finalizeWithFollowup.

Fix: persist the most recent runFollowup callback per queue key in
FOLLOWUP_RUN_CALLBACKS (drain.ts).  enqueueFollowupRun now calls
kickFollowupDrainIfIdle after a successful push; if a cached
callback exists and no drain is running it calls scheduleFollowupDrain
to restart immediately.  clearSessionQueues cleans up the callback
cache alongside the queue state.

* fix: avoid stale followup drain callbacks (openclaw#31902) (thanks @Lanfei)

* fix(synology-chat): read cfg from outbound context so incomingUrl resolves

* fix: require openclaw.extensions for plugin installs (openclaw#32055) (thanks @liuxiaopai-ai)

---------

Co-authored-by: Andrii Furmanets <furmanets.andriy@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Saurabh <skmishra1991@gmail.com>
Co-authored-by: stone-jin <1520006273@qq.com>
Co-authored-by: scotthuang <scotthuang@tencent.com>
Co-authored-by: User <user@example.com>
Co-authored-by: scoootscooob <zhentongfan@gmail.com>
Co-authored-by: justinhuangcode <justinhuangcode@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: AytuncYildizli <cryptosquanch@gmail.com>
Co-authored-by: bmendonca3 <bmendonca3@users.noreply.github.com>
Co-authored-by: Jealous <CooLanfei@163.com>
Co-authored-by: white-rm <zhang.xujin@xydigit.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: slack Channel integration: slack size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slack mention causes "Cannot read properties of undefined (reading 'includes')" error

2 participants