Account configs inherit channel-level fields at runtime (e.g.,
resolveTelegramAccount shallow-merges top-level and account values).
An account can set dmPolicy='allowlist' and rely on the parent's
allowFrom, so validating allowFrom on the account object alone
incorrectly rejects valid multi-account configs.
Removes requireAllowlistAllowFrom and requireOpenAllowFrom from all
account-level schemas (Telegram, Signal, IRC, iMessage, BlueBubbles).
Top-level config schemas still enforce the validation.
Addresses Codex review feedback on #27936.
When dmPolicy is set to "allowlist" but allowFrom is missing or empty,
all DMs are silently dropped because no sender can match the empty
allowlist. This is a common pitfall after upgrades that change how
allowlist files are handled (e.g., external allowlist-dm.json files
being deprecated in favor of inline allowFrom arrays).
Changes:
- Add requireAllowlistAllowFrom schema refinement (zod-schema.core.ts)
- Apply validation to all channel schemas: Telegram, Discord, Slack,
Signal, IRC, iMessage, BlueBubbles, MS Teams, Google Chat, WhatsApp
- Add detectEmptyAllowlistPolicy to doctor-config-flow.ts so
"openclaw doctor" surfaces a clear warning with remediation steps
- Add 12 test cases covering reject/accept for multiple channels
Fixes#27892
The config schema validates provider api fields against ModelApiSchema,
but openai-codex-responses was missing from the allowed values. This
forces users to set api: "openai-responses" for the openai-codex
provider, which routes requests to api.openai.com/v1/responses instead
of chatgpt.com/backend-api/codex/responses, causing HTTP 401 errors
because Codex OAuth tokens lack api.responses.write scope for the
standard OpenAI Responses endpoint.
The runtime already supports openai-codex-responses throughout: model
registry, stream dispatch (streamOpenAICodexResponses), and provider
detection (OPENAI_MODEL_APIS set). Only the config schema was missing
the literal.
Prevent gateway startup failures when plugins.entries contains stale or removed plugin ids by downgrading unknown entry keys from validation errors to warnings.
Made-with: Cursor
(cherry picked from commit 34ef28cf63)
- reject new lane enqueues once gateway drain begins
- always reset lane draining state and isolate onWait callback failures
- persist per-session abort cutoff and skip stale queued messages
- avoid false 600s agentTurn timeout in isolated cron jobs
Fixes#27407Fixes#27332Fixes#27427
Co-authored-by: Kevin Shenghui <shenghuikevin@github.com>
Co-authored-by: zjmy <zhangjunmengyang@gmail.com>
Co-authored-by: suko <miha.sukic@gmail.com>
Reimplements and consolidates related work:
- #24339 stale disconnect/destroyed session guards
- #25312 voice listener cleanup on stop
- #23036 restore @snazzah/davey runtime dependency
Adds Discord voice DAVE config passthrough, repeated decrypt failure
rejoin recovery, regression tests, docs, and changelog updates.
Co-authored-by: Frank Yang <frank.ekn@gmail.com>
Co-authored-by: Do Cao Hieu <admin@docaohieu.com>
Land #25538 by @chilu18 to keep legacy google-antigravity-auth config entries non-fatal after removal (see #25862).
Co-authored-by: chilu18 <chilu.machona@icloud.com>
When a third-party channel plugin declares a channel ID that differs from
its plugin ID (e.g. plugin id="apn-channel", channels=["apn"]), the
doctor plugin auto-enable logic was using the channel ID ("apn") as the
key for plugins.entries, producing an entry that fails config validation:
Error: plugins.entries.apn: plugin not found: apn
Root cause: resolveConfiguredPlugins iterated over cfg.channels keys and
used each key directly as both the channel ID (for isChannelConfigured)
and the plugin ID (for plugins.entries). For built-in channels these are
always the same, but for third-party plugins they can differ.
Fix: load the installed plugin manifest registry and build a reverse map
from channel ID to plugin ID. When a cfg.channels key does not resolve to
a built-in channel, look up the declaring plugin's manifest ID and use
that as the pluginId in the PluginEnableChange, so registerPluginEntry
writes the correct plugins.entries["apn-channel"] key.
The applyPluginAutoEnable function now accepts an optional manifestRegistry
parameter for testing, avoiding filesystem access in unit tests.
Fixes#25261
Co-Authored-By: Claude <noreply@anthropic.com>