Skip to content

Telegram Integration with Cross-Provider Session Sharing#22

Closed
arnemoor wants to merge 12 commits intoopenclaw:mainfrom
arnemoor:feat/telegram-integration
Closed

Telegram Integration with Cross-Provider Session Sharing#22
arnemoor wants to merge 12 commits intoopenclaw:mainfrom
arnemoor:feat/telegram-integration

Conversation

@arnemoor
Copy link
Copy Markdown

@arnemoor arnemoor commented Dec 6, 2025

Overview

Adds native Telegram as a messaging provider alongside the existing Twilio/WhatsApp support, with the ability to share Claude sessions across providers.

Key Changes

Telegram Provider (src/telegram/)

  • Full Telegram client using GramJS (MTProto)
  • Login flow with phone/2FA support
  • Message monitoring, sending, and media download
  • Phone number normalization to E.164 format

Multi-Provider Relay (src/cli/multi-relay.ts)

  • Run multiple providers concurrently (--providers twilio,telegram)
  • Unified message handling across providers
  • Aligned console logging for multi-provider mode

CLI Updates

  • warelay relay --providers telegram or --providers twilio,telegram
  • warelay identity command for managing cross-provider mappings
  • Telegram-specific options: --telegram-session, --telegram-allow-from

Cross-Provider Session Sharing (detailed)

The session sharing architecture allows a user to seamlessly continue their Claude conversation when switching between WhatsApp and Telegram.

Identity Mapping System (src/identity/)

// ~/.clawdis/identity-map.json

{
"version": 1,
"mappings": {
    "arne": {
    "id": "arne",
    "name": "Arne Moor",
    "identities": {
        "whatsapp": "+41791234567",
        "telegram": "123456789"
    },
    "createdAt": "...",
    "updatedAt": "..."
    }
}
}

How it works:

  1. findMappingByIdentity(provider, rawId) - Looks up if a provider identity (e.g., WhatsApp phone or Telegram user ID) is mapped to a shared identity
  2. normalizeSessionId(provider, rawId) - Called from deriveSessionKey() in sessions.ts:
  • If a mapping exists → returns the shared id (e.g., "arne")
  • If no mapping → returns provider-specific format (telegram:123456789 or +41791234567)
  1. Session storage - Sessions are keyed by the normalized ID in ~/.clawdis/sessions.json:
    {
    "arne": { "sessionId": "abc123", "updatedAt": 1234567890 }
    }

Result: Messages from both +41791234567 (WhatsApp) and 123456789 (Telegram) resolve to the same session key "arne", sharing Claude conversation state.

Management via CLI:
warelay identity add arne --whatsapp "+41791234567" --telegram "123456789"
warelay identity list
warelay identity remove arne

Add Telegram as a third messaging provider alongside web and twilio.

Core Features:
- Interactive login flow with phone/SMS/2FA authentication
- Send text and media messages (images, videos, audio, documents)
- Monitor incoming messages with auto-reply support
- Session management at ~/.clawdis/telegram/session/
- Full CLI integration (login, logout, status, send, relay commands)

Implementation Details:
- Uses telegram npm package for MTProto API access
- Supports both URL and local file media sending
- Cross-platform path handling (Windows/Unix)
- Optional Twilio env vars (supports Telegram-only usage)
- Minimal provider abstraction pattern
- Comprehensive test coverage (440 tests passing)

Changes:
- Add Telegram module (client, login, monitor, inbound, outbound, session)
- Add provider factory and base interfaces
- Wire Telegram functions into CLI deps
- Update env validation to make Twilio fields optional
- Add telegram to all CLI commands (login, logout, status, send, relay)
- Add null checks in Twilio code for optional env fields
- Fix send command to properly load session and connect
- Add local file support with cross-platform path handling
- Update login message to show correct ~/.clawdis path
- Add comprehensive tests and documentation

Basic Usage:
  warelay login --provider telegram
  warelay send --provider telegram --to "@user" --message "Hi"
  warelay send --provider telegram --to "@user" --media "/path/to/file.jpg"
  warelay relay --provider telegram

All tests pass (63 files, 440 tests). Zero TypeScript errors.
Implements identity mapping to allow linking WhatsApp, Telegram, and Twilio
identities for shared Claude conversation sessions across providers.

Core Features:
- Identity mapping storage in ~/.clawdis/identity-map.json
- Session ID normalization for unified sessions
- CLI commands for managing identity mappings
- Full backwards compatibility (opt-in feature)

New Identity Module (src/identity/):
- types.ts: Type definitions for identity mappings
- storage.ts: CRUD operations for identity persistence
- normalize.ts: Session ID normalization logic
- Comprehensive test coverage (29 tests passing)

CLI Commands (src/commands/identity.ts):
- identity link: Link multiple provider identities
- identity list: Show all identity mappings
- identity show: Display specific mapping details
- identity unlink: Remove identity mapping
- Input validation for E.164 phone numbers and Telegram usernames
- JSON output support for list/show commands

Session Integration:
- Made deriveSessionKey() async to support identity lookups
- Updated all callers: auto-reply, agent command, web provider
- Group conversations excluded from identity mapping
- Provider detection based on ID format

Documentation:
- docs/session-sharing.md: Comprehensive user documentation
- Architecture overview and use cases
- CLI usage examples and troubleshooting guide

Test Coverage:
- src/identity/normalize.test.ts: 11 tests for normalization
- src/identity/storage.test.ts: 18 tests for storage operations
- 100% coverage of identity module functionality

Files Changed:
- 10 new files (identity module, CLI, docs, tests)
- 5 modified files (sessions, CLI integration, auto-reply)

Build Status:
- All tests passing (29/29)
- Zero TypeScript errors
- Ready for production use
Implement --providers option to run multiple messaging providers
simultaneously in a single relay command. This enables seamless
session sharing across WhatsApp, Telegram, and Twilio.

Changes:
- Add src/cli/multi-relay.ts: Core multi-provider orchestration
  - Concurrent provider execution with Promise.allSettled
  - Graceful shutdown handling with AbortController
  - Unified startup and shutdown messaging
  - Per-provider error isolation

- Add selectProviders() to src/web/session.ts
  - Validates provider authentication before starting
  - Expands "auto" to all authenticated providers
  - User-friendly error messages for missing auth

- Update src/cli/program.ts relay command
  - Add --providers option (comma-separated list)
  - Refactor to build webTuning before multi-provider check
  - Pass suppressStartMessage=true to prevent duplicate logs

- Fix src/config/sessions.test.ts
  - Update tests to await async deriveSessionKey()

Tests:
- Add 11 new tests in src/cli/multi-relay.test.ts
  - Provider startup and shutdown
  - Concurrent execution
  - SIGINT handling
  - Error isolation
  - Console log alignment
- All 480 tests passing

Usage:
  warelay relay --providers web,telegram
  warelay relay --providers auto --verbose
Suppress individual provider startup messages when running in
multi-provider mode to avoid duplicate/conflicting console output.
The multi-relay orchestrator provides unified startup messaging.

Changes:
- Add suppressStartMessage to WebMonitorTuning type
- Update monitorWebProvider to suppress startup message when flag set
- Update Telegram monitor to suppress initial "Starting..." message
- Pass suppressStartMessage: true from multi-relay to both providers

Console output before:
  📡 Starting 2 provider(s): web, telegram
  📡 Starting Telegram relay...
  📡 Listening for personal WhatsApp Web inbound messages. Leave this running; Ctrl+C to stop.
  ✅ All 2 provider(s) active. Listening for messages... (Ctrl+C to stop)

Console output after:
  📡 Starting 2 provider(s): web, telegram
  ✅ All 2 provider(s) active. Listening for messages... (Ctrl+C to stop)
- Fix /new command session creation by checking isNewSession flag
- Add timestamp prefix to Telegram messages matching WhatsApp format
- Add reply logging for Telegram matching WhatsApp behavior
- Move think level token extraction before bodyPrefix to avoid false matches
- Update agent specs (claude, gemini, opencode) to send identity on new sessions
- Pass sessionIntro in command context for proper agent initialization
- Add Telegram handling to relay command when selected via pickProvider
- Add Telegram delivery support to agent --deliver command
- Add telegram: prefix to sender identifiers to prevent session ID collisions
- Update detectProvider to properly handle telegram: prefixed identifiers
- Document provider detection logic and session ID collision prevention

Fixes session ID collisions where Telegram users without usernames (numeric IDs
or phone numbers) were being misidentified as WhatsApp users, causing cross-
provider session leakage.
Document how provider prefixes prevent session ID collisions and explain
the identity-map.json feature for intentional cross-provider session sharing.

Covers:
- Default isolated session behavior (telegram: prefix)
- Why isolation prevents context confusion
- How to use identity-map.json for intentional sharing
- Provider identifier format reference
- Update Full Configuration example to include Telegram identifiers
- Expand allowFrom documentation to show all supported formats
- Add note about telegram: prefix requirement in allowFrom lists
- Show examples of telegram usernames, phone numbers, and numeric IDs
- Fixed normalizeAllowFromEntry to properly handle telegram: prefix
- Removed unused telegram.allowFrom config field from schema
- Updated all documentation to use ~/.clawdis paths with legacy fallback notes
- Fixed selectProviders to include Twilio support
- Added provider disconnect in agent delivery
- Improved media type detection
- Made Telegram inbound media save buffer to disk for Claude access

All Telegram identifiers now require telegram: prefix in shared inbound.allowFrom config.
Fixed extractSenderIdentifier to always add + prefix to phone numbers
from GramJS, ensuring they match normalized allowFrom entries.

Without this fix, Telegram senders with phone-based identifiers would
be blocked when using allowFrom whitelists because:
- GramJS returns phone as "123456789"
- normalizeAllowFromEntry expects "+123456789"
- Comparison fails: telegram:123456789 != telegram:+123456789

Now all phone identifiers are consistently normalized to telegram:+phone.
Fixes three critical bugs in Telegram integration:

1. Case-insensitive username matching
   - Telegram usernames are case-insensitive, but the API returns them with original casing
   - Now lowercase all usernames when extracting sender identifier to match config entries
   - Fixes: messages from @arnemoor now match config entry telegram:@arnemoor

2. Entity resolution for sending replies
   - resolveEntity() now strips telegram: prefix before resolving users/chats
   - Fixes: "Could not resolve Telegram entity: telegram:@username" errors when sending replies

3. Improved skip logging
   - Messages skipped due to allowFrom filtering now always logged (not just in verbose mode)
   - Uses clear emoji indicator: ⏭️ Skipped message from...
@arnemoor
Copy link
Copy Markdown
Author

arnemoor commented Dec 6, 2025

This one is 101 commits behind your changes from yesterday, if you like the approach either take it or let me know if I should re-implement on the current main.

Applied formatting fixes to 21 files:
- Fixed import ordering
- Normalized indentation
- Wrapped long lines

No logic changes, formatting only.
@steipete
Copy link
Copy Markdown
Contributor

steipete commented Dec 7, 2025

Thank you! Yeah I wanted to first get the foundation right, revamp session management and so on before tackling Telegram.

I'll see if I can salvage anything from here - defo helps with planning, thank you!

@tiagoefreitas
Copy link
Copy Markdown

@steipete this or works more like the whatsapp version, my pr uses the bot api that does not need a phone number and is better for this use case. This pr is better when we want clawdis to reply to any message from anyone or proactively send messages. I think both could be integrated, the bot api to communicate with clawdis, and the user api to ask clawdis to send messsages/replies on our behalf

@steipete
Copy link
Copy Markdown
Contributor

steipete commented Dec 8, 2025

I went with the bot-version, seems sufficient for what. we need here + safer? https://github.com/tiagoefreitas/warelay
Did you consider both when building this?

@tiagoefreitas
Copy link
Copy Markdown

I went with the bot-version, seems sufficient for what. we need here + safer? https://github.com/tiagoefreitas/warelay

Did you consider both when building this?

I did consider and agree bot is safer but I still like this PR so the agent can act on my behalf but would need some safety tweaks like approved destinations, prefix/suffix saying it's not me writing, and should probably be a tool/cli and not in clawdis itself

@tiagoefreitas
Copy link
Copy Markdown

About multi provider switching I don't think it's necessary between WhatsApp and telegram but it's interesting between those and the web cli, and adding /new and /resume commands to the telegram bot commands.

@arnemoor arnemoor closed this Dec 8, 2025
dgarson referenced this pull request in dgarson/clawdbot Feb 2, 2026
feat(ui): add command history & recents to command palette
linustan pushed a commit to linustan/Komatachi that referenced this pull request Feb 5, 2026
…trator deferred

Agent communicates via structured JSON-lines on stdin/stdout. Orchestrator
is a separate process that owns agent processes and handles out-of-band
concerns. Orchestrator reads agent state from conversation store on disk.

https://claude.ai/code/session_019ZjUw1xvyg4ovLRrdQySpv
linustan added a commit to linustan/Komatachi that referenced this pull request Feb 5, 2026
Implement Decision openclaw#22: agent as headless worker process communicating
via stdin/stdout JSON-lines. Rust CLI spawns a Docker container running
the TypeScript agent, exchanges messages over a simple protocol.

- src/index.ts: application entry point wiring all modules + Anthropic SDK
- cli/: Rust REPL that builds/spawns Docker, manages container lifecycle
- Dockerfile: multi-stage build (test, typecheck, app)
- npm/node sandboxed to Docker only; lockfile generated via Docker
alexprime1889-prog pushed a commit to alexprime1889-prog/moltbot that referenced this pull request Feb 8, 2026
frodo-harborbot added a commit to harborworks/openclaw that referenced this pull request Feb 16, 2026
…nclaw#22)

* fix: add env_file to database service so it reads DATABASE_PASSWORD from .env.prod

Without env_file, the ${DATABASE_PASSWORD:-postgres} interpolation always
falls back to 'postgres' because the variable is never set in the database
service's environment. The backend reads .env.prod and gets the real password,
causing an auth mismatch.

* fix: build schema package before running tests

The @harbor-app/schema package must be built before backend tests can
resolve its exports. Without this, vitest fails with 'Failed to resolve
entry for package @harbor-app/schema'.
ivanuser added a commit to ivanuser/cortex that referenced this pull request Feb 23, 2026
…claw#22, openclaw#23)

Issue openclaw#22 — QR Code Pairing:
- QRPairModal component: generates QR with encoded gateway URL + invite code + role
- Nodes page: QR Pair button in header toolbar
- SetupWizard: detects ?qr= URL parameter, auto-fills gateway URL and invite code
- Uses invite.create RPC to generate one-time invite codes (falls back if unavailable)
- QR codes auto-expire after 5 minutes with regenerate prompt

Issue openclaw#23 — LAN Auto-Approve:
- Added gateway.security.lanAutoApprove config option (default: false)
- Added gateway.security.lanAutoApproveRole config option (default: 'operator')
- Config types (GatewaySecurityConfig) and zod schema validation
- Message handler checks isPrivateOrLoopbackAddress for LAN clients
- LAN auto-approved devices get securityRole from config
- Audit logged as device.pair.lan-auto-approve
- approveReason field added to PairedDevice type
- Nodes page shows 'LAN auto-approved' badge on auto-approved devices

Also includes invite/pairing code validation in connect handshake.
bottlerex pushed a commit to bottlerex/openclaw that referenced this pull request Feb 23, 2026
- git rm --cached config/openclaw.json (contains bot token, was already in .gitignore but still tracked)
- Added: logs/, metrics/, ssh-keys/, patches/, test files, plist files, config subdirs
- Fixes issue openclaw#22: bot token no longer in version control
songliu0403-rgb pushed a commit to songliu0403-rgb/openclaw that referenced this pull request Feb 26, 2026
emmalone added a commit to emmalone/openclaw that referenced this pull request Mar 1, 2026
speculatingwook added a commit to Pronto-Lab/prontoclaw that referenced this pull request Mar 3, 2026
- Move harness design doc from docs/tools/ to custom-docs/
- Add harness section (openclaw#22) to PRONTOLAB.md
- Remove SSH connection details from all prontolab docs (public repo)

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Piboonsak referenced this pull request in Piboonsak/openclaw_github Mar 3, 2026
Config changes (#33):
- Switch primary model to anthropic/claude-sonnet-4-5 (Claude Sonnet 4.6)
- Add model to deploy.sh post-deploy config, update fallback chain

Nginx changes (#32, #21):
- Increase /line/ proxy_read_timeout from 120s to 300s for complex agent responses

Docker build (#39):
- Enable OPENCLAW_INSTALL_BROWSER=1 build-arg to include Chromium in image

Deploy pipeline fix:
- deploy-vps.yml now actually applies nginx config (was only staging to .new)
- Added backup + rollback safety for nginx config changes
- Removed broken nginx path from deploy.sh (was referencing wrong VPS path)

Issues addressed: #9, #20, #21, #22, #23, #32, #33, #37, #39, #42, openclaw#45, openclaw#46
guiramos added a commit to butley/openclaw that referenced this pull request Mar 4, 2026
…#15-openclaw#22)

Each patch dir now has a README.md (human context) and 001.patch
(git format-patch for mechanical re-application via git apply --3way).
Updated registry, verify script, and re-application order docs.
benieralexis-sudo pushed a commit to benieralexis-sudo/openclaw that referenced this pull request Mar 6, 2026
- openclaw#6 Reply classifier hallucination pattern: regex plus specifique (exige prenom+nom)
- openclaw#7 Fuzzy match domaine: ajoute verification local part + nom similaire
- openclaw#9 callOpenAI duplique: delegue au shared-nlp (tracking budget)
- openclaw#22 Collision cron 14h: mini-cycles decales 10h/12h/15h/17h
- openclaw#24 Bounce rate dilue: remplace derniere entree success par bounce
- openclaw#26 API chat+HITL sans auth: verification x-api-token/authorization
- openclaw#27 Passwords dashboard: generes aleatoirement (24 chars)
- Bonus: commande "statut systeme" protegee admin-only

28/28 bugs de l'audit corriges. 0 restant.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
elliot-ylambda pushed a commit to elliot-ylambda/magister-openclaw that referenced this pull request Mar 7, 2026
…penclaw#22)

Removes misleading foundation text, makes unsubscribe link always
visible, and adds CAN-SPAM compliant copy to email footer.

Co-authored-by: Claude Opus 4.6 <[email protected]>
lucasmpramos added a commit to butley/openclaw that referenced this pull request Mar 9, 2026
Merges 33 commits from work branch:
- WhatsApp login tool HTTP invoke (openclaw#21/openclaw#25)
- Audio inbound transcription for webchat (openclaw#21)
- TTS audio playback in chat (openclaw#22)
- /media endpoint for audio/image serving (openclaw#19)
- image_generate tool with Gemini (openclaw#20)
- imageReady/mediaReady event pipeline (openclaw#22)
- Chat.send internal routing simplification (openclaw#23)
- Silent reply filter removal (openclaw#24)
- ThinkingDefault shortcut (openclaw#26)

Conflict resolution:
- patches/README.md: unified numbering (our #2-18 + his openclaw#19-26)
- patches/verify-patches.sh: combined both check sets (24 total)
- server-methods/chat.ts: used work version as base (has media pipeline),
  route resolution removal from openclaw#23 is intentional for webchat

Build: clean. Patches: 24/24 passing.

Co-authored-by: Bob
krandder added a commit to krandder/openclaw that referenced this pull request Mar 11, 2026
- Track created and last_connected timestamps in slot map (columns 4-5, backward compatible)
- Detect exited sessions via pane_current_command (bash/zsh = dead)
- Show relative time ("2h ago") and red "exited" status in list/picker
- Sync remote pane titles back to slot map on fetch
- Add --name flag, register_new_slot helper, auto-register unknown slots
CyberSpencer added a commit to CyberSpencer/openclaw that referenced this pull request Mar 19, 2026
Implements openclaw#22 with worklet conversational capture + format propagation.
zhyongrui added a commit to zhyongrui/openclaw that referenced this pull request Mar 20, 2026
wzfukui added a commit to wzfukui/openclaw that referenced this pull request Mar 20, 2026
…openclaw#22)

Phase 1: Revoke handling
- Listen for message.revoked WS events
- Track messageId→streamId mapping, deliver skips revoked blocks
- Enqueue system event so agent session is notified

Phase 4: Stream cancel abort
- Listen for stream.cancel and task.cancel WS events
- AbortController per active stream, deliver checks signal.aborted
- Send cancellation progress event to frontend
- Graceful: partial content already sent remains visible

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
vincentkoc added a commit that referenced this pull request Mar 23, 2026
- sdk-runtime.md: add missing required params (runId, timeoutMs) to
  runEmbeddedPiAgent example
- sdk-provider-plugins.md: add missing onModelSelected hook (#22),
  clarify capabilities is data not callable, drop misleading '21' count
frankekn pushed a commit to artwalker/openclaw that referenced this pull request Mar 23, 2026
- sdk-runtime.md: add missing required params (runId, timeoutMs) to
  runEmbeddedPiAgent example
- sdk-provider-plugins.md: add missing onModelSelected hook (openclaw#22),
  clarify capabilities is data not callable, drop misleading '21' count
furaul pushed a commit to furaul/openclaw that referenced this pull request Mar 24, 2026
- sdk-runtime.md: add missing required params (runId, timeoutMs) to
  runEmbeddedPiAgent example
- sdk-provider-plugins.md: add missing onModelSelected hook (openclaw#22),
  clarify capabilities is data not callable, drop misleading '21' count
npmisantosh pushed a commit to npmisantosh/openclaw that referenced this pull request Mar 25, 2026
- sdk-runtime.md: add missing required params (runId, timeoutMs) to
  runEmbeddedPiAgent example
- sdk-provider-plugins.md: add missing onModelSelected hook (openclaw#22),
  clarify capabilities is data not callable, drop misleading '21' count
PotatoParser added a commit to Lilac-Labs/openclaw that referenced this pull request Mar 26, 2026
* fix(delivery-queue): increment retryCount on deferred entries when time budget exceeded

When delivery recovery ran out of the 60s time budget, remaining pending
entries were silently deferred to the next restart with no retryCount
increment. This caused them to loop forever across restarts, never hitting
MAX_RETRIES and never moving to failed/.

Fix: call failDelivery() on each remaining entry before breaking out of
the recovery loop (both the deadline check and the backoff-exceeds-deadline
check). This increments retryCount so that entries eventually exhaust
MAX_RETRIES and are permanently skipped.

Fixes openclaw#24353

* fix(delivery-queue): break immediately on deadline instead of failing all remaining entries

P1-C: After now >= deadline, the old code would iterate all remaining queue
entries and call failDelivery() on each — O(n) work that nullified the
maxRecoveryMs wall-clock cap on large queues.

Fix: break out of the recovery loop immediately when the deadline is exceeded.
Remaining entries are picked up on next startup unchanged (retryCount not
incremented). The deadline means 'stop here', not 'fail everything remaining'.

* fix(delivery-queue): align test assertion and JSDoc with 'next startup' log message

* fix(browser): add ChildProcessWithoutNullStreams cast for @types/node compat

The stdio tuple overload resolves differently across @types/node versions
(v20 vs v24/v25). Cast the spawn() result to ChildProcessWithoutNullStreams
to ensure proc.stderr?.on/off type-checks regardless of installed @types/node.

* test(delivery-queue): align test assertion with 'next startup' log message

* fix(delivery-queue): increment retryCount on deadline-deferred entries

Codex P1: entries deferred by the recovery time budget kept retryCount=0
forever, so they could loop across restarts without ever reaching MAX_RETRIES.

After breaking on deadline, call failDelivery() for all remaining entries
so retryCount is incremented. Entries stay in queue until MAX_RETRIES is
reached and they are pruned normally.

Also updates the maxRecoveryMs test to assert retryCount=1 on deferred entries.

* fix(ci): restore delivery queue branch checks

* fix(plugins): make metadata generator formatter portable

* fix(image): deprecate legacy skill and clarify auth

* docs(image): remove duplicate typical values bullet

* fix: harden image auth env lookups (openclaw#52552) (thanks @vincentkoc)

* test(mattermost): cover directory discovery

* test(msteams): cover store and live directory helpers

* fix(mattermost): honor replyToMode off for threaded messages

* perf(reply): lazy-load runner execution and memory

* fix(plugins): remove metadata generator conflict markers

* test(nextcloud-talk): cover inbound behavior branches

* test(irc): cover inbound behavior branches

* test: slim outbound test import graphs

* perf: remove remaining unit thread pins

* perf(reply): lazy-load usage cost resolution

* test(googlechat): cover security normalization

* perf(reply): lazy-load context token lookup

* style(format): fix extension test drift

* test: centralize cli runtime capture helpers

* refactor: reuse shared cli runtime test mocks

* fix: restore bundled plugin metadata generator

* fix(telegram): add allow_sending_without_reply to prevent lost messages

When a Telegram message that OpenClaw is replying to gets deleted before
delivery, the Telegram API rejects the entire sendMessage call with
"message to be replied not found". This causes the bot's response to be
silently lost and stuck in the failed delivery queue permanently.

Setting allow_sending_without_reply: true tells Telegram to deliver the
message as a standalone message if the reply target no longer exists,
instead of failing the entire request.

Applied to all 6 locations across 4 source files where
reply_to_message_id is set:
- send.ts: buildTelegramReplyParams (both reply_parameters and plain reply)
- bot/delivery.send.ts: buildTelegramSendParams
- draft-stream.ts: draft stream reply params
- bot-handlers.runtime.ts: error reply messages (file too large, media download failed)

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(telegram): update test expectations for allow_sending_without_reply

Update exact-match test assertions in send.test.ts to include the new
allow_sending_without_reply: true parameter. Tests using objectContaining
already pass, but several tests use exact object matching.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix: finish telegram reply fallback landing (openclaw#52524) (thanks @moltbot886)

* refactor: extract single-provider plugin entry helper

* refactor: add provider onboarding preset appliers

* refactor: share parsed channel allowlist prompts

* refactor: share channel setup status helpers

* fix: export provider-entry plugin sdk subpath

* style: format plugin sdk helper updates

* fix(docs): code-verified fixes from deep reference audit

- sdk-runtime.md: add missing required params (runId, timeoutMs) to
  runEmbeddedPiAgent example
- sdk-provider-plugins.md: add missing onModelSelected hook (openclaw#22),
  clarify capabilities is data not callable, drop misleading '21' count

* test: fix googlechat security typing drift

* perf: remove stale unit isolated entry

* refactor(outbound): split delivery queue storage and recovery

* fix(docs): remaining code audit fixes

- sdk-entrypoints.md: fix mislabeled 'Channel entry options' heading
  (should be 'Options' — these are definePluginEntry options, not
  channel-specific)
- sdk-overview.md: add 4 missing API object fields (version, description,
  source, rootDir) from OpenClawPluginApi type

* perf(reply): split usage line helpers

* perf(reply): narrow queue imports

* test(msteams): cover graph helpers

* test(msteams): cover upload and webhook helpers

* refactor: harden generated-file guards and provider ids

* fix: restore main gate after type updates

* fix(plugins): accept media-understanding id hints

* test: default scoped vitest configs to no-isolate

* test(msteams): cover poll and file-card helpers

* test: fix provider config typing drift

* perf: default channel vitest lanes to threads

* perf(reply): lazy-load media path normalization

* style(format): fix msteams test drift

* refactor(plugins): move remaining channel and provider ownership out of src

* refactor(plugins): finish provider and whatsapp cleanup

* fix(gateway): pass process.env in status command probe auth to resolve SecretRef

Fixes openclaw#52360

resolveGatewayProbeAuthSafe was called from status-all.ts without an
env argument, causing the credential resolution chain to fall back to
an empty object instead of process.env. This made env-backed SecretRef
tokens (gateway.auth.token, Telegram botToken, etc.) appear unresolved
in the status command path even when the runtime was healthy.

Added process.env as default fallback in buildGatewayProbeCredentialPolicy
and passed env explicitly from status-all.ts callers.

Related: openclaw#33070, openclaw#38973, openclaw#39415, openclaw#46014, openclaw#49730

* fix(status): resolve only selected probe-auth branch and fix plain status path

Address two Codex P1/P2 issues:

1. (P1) Plain 'openclaw status' and 'openclaw status --json' still went
   through the sync resolveGatewayProbeAuthSafe path in
   status.gateway-probe.ts, which cannot expand SecretRef objects.
   Switched to async resolveGatewayProbeAuthSafeWithSecretInputs.

2. (P2) status-all.ts was eagerly resolving both local and remote probe
   auth before deciding which to use. A stale SecretRef in the unused
   branch could abort the command. Collapsed to a single resolution
   call using the correct mode upfront.

Updated status.scan.test.ts to use mockResolvedValue since
resolveGatewayProbeAuthResolution is now async.

* fix(status): await resolveGatewayProbeAuthResolution in scan.shared

Function is now async after switching to resolveGatewayProbeAuthSafeWithSecretInputs.
Missing await caused TS error: Property 'auth' does not exist on type 'Promise<...>'.

* fix: finish gateway probe auth landing (openclaw#52513) (thanks @CodeForgeNet)

* fix: finish gateway probe auth landing (openclaw#52513) (thanks @CodeForgeNet)

* test: clear msteams gate drift for gateway probe auth landing (openclaw#52513) (thanks @CodeForgeNet)

* fix(exec): return plain-text tool result on failure instead of raw JSON

When an exec command fails (e.g. timeout), the tool previously rejected
with an Error, which the tool adapter caught and wrapped in a JSON object
({ status, tool, error }). The model then received this raw JSON as the
tool result and could parrot it verbatim to the user.

Now exec failures resolve with a proper tool result containing the error
as human-readable text in content[], matching the success path structure.
The model sees plain text it can naturally incorporate into its reply.

Also fixes a pre-existing format issue in update-cli.test.ts.

Fixes openclaw#52484

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix: finish exec tool failure landing (openclaw#52508) (thanks @martingarramon)

* fix(openshell): bundle upstream cli fallback

* perf(reply): lazy-load session store writes

* fix(build): restore plugin-sdk and line compat after refactor

* refactor(kilocode): route shared model constants through core seam

* refactor(plugin-sdk): route core provider and telegram seams through sdk barrels

* fix(acp): preserve hidden thought chunks from gateway chat

* fix(docs): rename 'Channel Options' to 'Options' in sdk-entrypoints

This heading labels definePluginEntry options (generic, not channel-specific).
Another agent reverted the previous fix during a merge.

* fix(line): narrow plugin-sdk seams after refactor

* test(voice-call): cover helper utilities

* test(voice-call): cover manager and api helpers

* fix(acp): preserve hidden thought replay on session load

* test(voice-call): cover twilio and reaper helpers

* docs(changelog): note ACP hidden thought replay fix

* test(voice-call): cover utility and tailscale helpers

* fix(ci): resync generated baselines and line runtime seam

* fix(docs): remove duplicate '### Options' headings (MD024)

* fix(ci): restore plugin manifests and boundary tests

* style(docs): format sdk entrypoints doc

* docs(config): refresh generated baseline

* test(voice-call): cover outbound call flow helpers

* fix(ci): repair tts and matrix refactor fallout

* fix(ci): repair voice-call typing and provider contracts

* fix(ci): satisfy voice-call typing and extension boundaries

* Remove personal references from docs (openclaw#25260)

* docs: remove personal references from AGENTS.md

* docs: remove personal reference from sag skill

* docs: note generic agent guidance cleanup

* Update CHANGELOG.md

---------

Co-authored-by: Josh Lehman <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>

* fix(plugins): route keyed queue imports through core (openclaw#52608)

* fix(matrix): preserve send aliases and voice intent

* fix(build): repair stale plugin sdk surfaces

* fix(plugin-sdk): export line runtime subpath

* fix(auth): route copilot login through sdk seam

* feat(web-search): add bundled Exa plugin (openclaw#52617)

* test(msteams): await async setup status lines

* fix(whatsapp): remove outbound runtime cycle

* fix(plugin-sdk): fast-path root diagnostic subscriptions

* fix(exa): align freshness typing and config docs

* fix(matrix): avoid touching dropped room bindings

* fix(web-search): align Exa plugin with current API

* docs(tools): add DuckDuckGo Search provider page

New page: tools/duckduckgo-search.md
- Key-free fallback provider, no API key needed
- Clear Warning about unofficial HTML-based integration
- Limitations section covering bot-challenge risk and reliability
- CardGroup showing good-for vs not-recommended-for use cases

Updated: tools/web.md with DuckDuckGo in CardGroup and comparison table
Updated: docs.json nav and redirect

* test(telegram): align webhook grammy mock

* docs(tools): add Exa Search page, align all search provider docs

New page: tools/exa-search.md
- Neural/keyword/hybrid search modes with content extraction
- Tool parameters including contents (highlights, text, summary)
- Search mode reference table

Rewritten: tools/duckduckgo-search.md
- Aligned to consistent template (Setup, Config, Tool parameters, Notes, Related)
- Simplified from previous version

Aligned across all providers:
- Every search page now ends with a consistent ## Related section
- Replaced 'See [Web tools]' with proper Related links
- Added Exa + DuckDuckGo to web.md overview CardGroup and comparison table
- Added Exa to docs.json nav and redirects

* fix(telegram): inject media loader through bot deps

* fix(ci): harden telegram seams and cap job timeouts

* docs(tools): update Exa Search notes for current API behavior

Add notes about default highlights contents, highlightScores/summary
preservation from responses, description resolution order, and
100-result cap.

* perf: add vitest test perf workflows

* fix(ci): harden changed extension diff fallback

* fix(telegram): harden grammy seams across tests

* refactor: extract exec outcome and tool result helpers

* test: isolate exec foreground failure coverage

* fix(test): allow empty extension lane

* perf: enable vitest fs module cache by default

* fix(cli): route plugin logs to stderr during --json output

* fix(cli): route deferred plugin logs to stderr in status --json

* fix: keep status --json stdout clean (openclaw#52449) (thanks @cgdusek)

* refactor(ci): collapse fast setup jobs into preflight

* fix(exec): accept runtime failure kind in formatter

* fix: include .env file vars in gateway service environment on install

When building the gateway install plan, read and parse
~/.openclaw/.env (or $OPENCLAW_STATE_DIR/.env) and merge those
key-value pairs into the service environment at the lowest
priority — below config env vars, auth-profile refs, and the
core service environment (HOME, PATH, OPENCLAW_*).

This ensures that user-defined secrets stored in .env (e.g.
BRAVE_API_KEY, OPENROUTER_API_KEY, DISCORD_BOT_TOKEN) are
embedded in the LaunchAgent plist (macOS), systemd unit (Linux),
and Scheduled Task (Windows) at install time, rather than
relying solely on the gateway process loading them via
dotenv.config() at startup.

Previously, on macOS the LaunchAgent plist never included .env
vars, which meant:
- launchctl print did not show user secrets (hard to debug)
- Child processes spawned before dotenv loaded had no access
- If the same key existed in both .env and the plist, the stale
  plist value won via dotenv override:false semantics

Dangerous host env vars (NODE_OPTIONS, LD_PRELOAD, etc.) are
filtered using the same security policy applied to config env
vars.

Fixes openclaw#37101
Relates to openclaw#22663

* fix: normalize env var keys and isolate tests from real .env

- Apply normalizeEnvVarKey({ portable: true }) before security
  filtering, matching the established pattern in env-vars.ts.
  Rejects non-portable key names (spaces, special chars) that
  would produce invalid plist/systemd syntax.

- Isolate existing tests from the developer's real ~/.openclaw/.env
  by providing a temp HOME directory, preventing flaky failures
  when the test machine has a populated .env file.

* fix: narrow exec exit failure kind typing

* fix(test): isolate flaky extension lanes

* feat(web-search): add DuckDuckGo bundled plugin (openclaw#52629)

* feat(web-search): add DuckDuckGo bundled plugin

* chore(changelog): restore main changelog

* fix(web-search): harden DuckDuckGo challenge detection

* refactor: split durable service env helpers

* refactor: extract gateway install token helpers

* fix(web-search): mark DuckDuckGo experimental

* docs(tools): update DuckDuckGo Search for landed plugin code

- Mark as experimental (not just unofficial)
- Add region and safeSearch tool parameters (from DDG schema)
- Add plugin config example for region/safeSearch defaults
- Document auto-detection order (100 = last)
- Note SafeSearch defaults to moderate
- Verified against extensions/duckduckgo/src/

* fix(agents): deny local MEDIA paths for MCP results

* Usage: include reset and deleted session archives (openclaw#43215)

Merged via squash.

Prepared head SHA: 49ed6c2
Co-authored-by: rcrick <[email protected]>
Co-authored-by: frankekn <[email protected]>
Reviewed-by: @frankekn

* docs(tools): soften DDG wording (scrapes -> pulls/gathers)

* fix(build): add stable memory-cli dist entry (openclaw#51759)

Co-authored-by: oliviareid-svg <[email protected]>
Co-authored-by: Frank <[email protected]>

* refactor!: drop legacy CLAWDBOT env compatibility

* refactor!: remove moltbot state-dir migration fallback

* fix(gateway): preserve async hook ingress provenance

* fix(ci): write dist build stamp after builds

* perf: trim vitest hot imports and refresh manifests

* fix(security): unwrap time dispatch wrappers

* fix(plugin-sdk): fall back to src root alias files

* fix(ci): skip docs-only preflight pnpm audit

* docs(changelog): note time exec approval fix

* docs: refresh plugin-sdk api baseline

* fix(runtime): make dist-runtime staging idempotent

* fix(media): bound remote error-body snippet reads

* fix(gateway): gate internal command persistence mutations

* fix: restrict remote marketplace plugin sources

* fix(runtime): skip peer resolution for bundled plugin deps

* docs(agents): prefer current test model examples

* fix(exec): escape invisible approval filler chars

* test(models): refresh example model fixtures

* fix(security): unify dispatch wrapper approval hardening

* fix(security): harden explicit-proxy SSRF pinning

* fix: gate synology chat reply name matching

* docs: clarify sessions_spawn ACP vs subagent policies

* refactor(exec): split wrapper resolution modules

* refactor(exec): make dispatch wrapper semantics spec-driven

* refactor(exec): share wrapper trust planning

* refactor(exec): rename wrapper plans for trust semantics

* fix: include .npmrc in onboard docker build

* test: trim docker live auth mounts

* Docs: refresh config baseline for Synology Chat

* refactor: clarify synology delivery identity names

* refactor: centralize synology dangerous name matching

* refactor: narrow synology legacy name lookup

* refactor: audit synology dangerous name matching

* refactor: dedupe synology config schema

* fix: normalize scoped vitest filter paths

* fix(voice-call): harden webhook pre-auth guards

* fix(synology-chat): fail closed shared webhook paths

* docs: credit nexrin in synology changelog

* test: fix base vitest thread regressions

* test: finish base vitest thread fixture fixes

* test(voice-call): accept oversize webhook socket resets

* test: honor env auth in gateway live probes

* fix: harden plugin docker e2e

* Docs: align MiniMax examples with M2.7

* fix(ci): restore stale guardrails and baselines

* Test: isolate qr dashboard integration suite

* Gateway: resolve fallback plugin context lazily

* fix: bind bootstrap setup codes to node profile

* fix(tlon): unify settings reconciliation semantics

* refactor(synology-chat): type startup webhook path policy

* docs(synology-chat): clarify multi-account webhook paths

* refactor: unify minimax model and failover live policies

* docs: sync minimax m2.7 references

* fix: harden Windows Parallels smoke installs

* docs: reorder unreleased changelog by user impact

* refactor: remove embedded runner cwd mutation

* Infra: support shell carrier allow-always approvals

* refactor: centralize bootstrap profile handling

* refactor: reuse canonical setup bootstrap profile

* fix(plugin-sdk): resolve hashed diagnostic events chunks

* fix(plugin-sdk): normalize hashed diagnostic event exports

* test: fix ci env-sensitive assertions

* fix(gateway): fail closed on unresolved discovery endpoints

* feat: add slash plugin installs

* fix(media): block remote-host file URLs in loaders

* fix(media): harden secondary local path seams

* test: harden no-isolate reply teardown

* docs(changelog): add Windows media security fix

* refactor(gateway): centralize discovery target handling

* test: narrow live transcript scaffolding strip

* test: fix ci docs drift and bun qr exit handling

* fix(browser): enforce node browser proxy allowProfiles

* refactor(media): share local file access guards

* test: stabilize ci test harnesses

* test: harden no-isolate test module resets

* fix(plugins): preserve live hook registry during gateway runs

* test: fix channel summary registry setup

* test: harden isolated test mocks

* chore(plugins): remove opik investigation checkpoints

* ACPX: align pinned runtime version (openclaw#52730)

* ACPX: align pinned runtime version

* ACPX: drop version example from help text

* test: stop leaking image workspace temp dirs

* fix(android): gate canvas bridge to trusted pages (openclaw#52722)

* fix(android): gate canvas bridge to trusted pages

* fix(changelog): note android canvas bridge gating

* Update apps/android/app/src/main/java/ai/openclaw/app/node/CanvasActionTrust.kt

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix(android): snapshot canvas URL on UI thread

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* test: isolate base vitest thread blockers

* fix: sync agent and autoreply e2e updates

* test: harden no-isolate mocked module resets

* docs: reorder unreleased changelog

* fix(changelog): note windows media path guardrails (openclaw#52738)

* fix: alphabetize web search provider listings

* docs: clarify unreleased breaking changes

* test: harden ci isolated mocks

* fix: align websocket stream fallback types

* test: finish no-isolate suite hardening

* style: format image-generation runtime tests

* fix(memory-core): register memory tools independently to prevent coupled failure (openclaw#52668)

Merged via admin squash because current required CI failures are inherited from base and match latest `main` failures outside this PR's `memory-core` surface.

Prepared head SHA: df7f968
Co-authored-by: artwalker <[email protected]>
Reviewed-by: @frankekn

* fix(status): recompute fallback context window (openclaw#51795)

* fix(status): recompute fallback context window

* fix(status): keep live context token caps on fallback

* fix(status): preserve fallback runtime context windows

* fix(status): preserve configured fallback context caps

* fix(status): keep provider-aware transcript context lookups

* fix(status): preserve explicit fallback context caps

* fix(status): clamp fallback configured context caps

* fix(status): keep raw runtime slash ids

* fix(status): refresh plugin-sdk api baseline

* fix(status): preserve fallback context lookup

* test(status): refresh plugin-sdk api baseline

* fix(status): keep runtime slash-id context lookup

---------

Co-authored-by: create <[email protected]>
Co-authored-by: Frank Yang <[email protected]>
Co-authored-by: RichardCao <[email protected]>

* fix(telegram): make buttons schema optional in message tool

The Telegram plugin injects a `buttons` property into the message tool
schema via `createMessageToolButtonsSchema()`, but without wrapping it
in `Type.Optional()`. This causes TypeBox to include `buttons` in the
JSON Schema `required` array.

In isolated sessions (e.g. cron jobs) where no `currentChannel` is set,
all plugin schemas are merged into the message tool. When the LLM calls
the message tool without a `buttons` parameter, AJV validation fails
with: `buttons: must have required property 'buttons'`.

Wrap the buttons schema in `Type.Optional()` so it is not required.

* fix: keep message-tool buttons optional for Telegram and Mattermost (openclaw#52589) (thanks @tylerliu612)

* test: update codex test fixtures to gpt-5.4

* fix: repair runtime seams after rebase

* fix: restore Telegram topic announce delivery (openclaw#51688) (thanks @mvanhorn)

When `replyLike.text` or `replyLike.caption` is an unexpected
non-string value (edge case from some Telegram API responses),
the reply body was coerced to "[object Object]" via string
concatenation. Add a `typeof === "string"` guard to gracefully
fall back to empty string, matching the existing pattern used
for `quoteText` in the same function.

Co-authored-by: Penchan <[email protected]>

* docs: sync generated release baselines

* test: isolate pi embedded model thread fixtures

* fix: restore provider runtime lazy boundary

* fix: preserve Telegram reply context text (openclaw#50500) (thanks @p3nchan)

* fix: guard Telegram reply context text (openclaw#50500) (thanks @p3nchan)

* fix: preserve Telegram reply caption fallback (openclaw#50500) (thanks @p3nchan)

---------

Co-authored-by: Ayaan Zaidi <[email protected]>

* fix: harden gateway SIGTERM shutdown (openclaw#51242) (thanks @juliabush)

* fix: increase shutdown timeout to avoid SIGTERM hang

* fix(telegram): abort polling fetch on shutdown to prevent SIGTERM hang

* fix(gateway): enforce hard exit on shutdown timeout for SIGTERM

* fix: tighten gateway shutdown watchdog

* fix: harden gateway SIGTERM shutdown (openclaw#51242) (thanks @juliabush)

---------

Co-authored-by: Ayaan Zaidi <[email protected]>

* build: prepare 2026.3.22-beta.1

* fix: restore provider runtime lazy boundary

* test: add parallels npm update smoke

* test: split pi embedded model thread fixtures

* fix: stop browser server tests from launching real chrome

* test: stabilize live provider docker probes

* fix: restart windows gateway after npm update

* test: isolate server-context browser harness imports

* test: inject model runtime hooks for thread-safe tests

* test: snapshot ci timeout investigation

* test: target gemini 3.1 flash alias

* test: stabilize trigger handling and hook e2e tests

* build: prepare 2026.3.22

---------

Co-authored-by: Stephen Schoettler <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
Co-authored-by: create <[email protected]>
Co-authored-by: moltbot886 <[email protected]>
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: CodeForgeNet <[email protected]>
Co-authored-by: Martin Garramon <[email protected]>
Co-authored-by: François Martin <[email protected]>
Co-authored-by: Josh Lehman <[email protected]>
Co-authored-by: Charles Dusek <[email protected]>
Co-authored-by: Kevin ONeill <[email protected]>
Co-authored-by: Rick_Xu <[email protected]>
Co-authored-by: rcrick <[email protected]>
Co-authored-by: frankekn <[email protected]>
Co-authored-by: oliviareid-svg <[email protected]>
Co-authored-by: oliviareid-svg <[email protected]>
Co-authored-by: Frank <[email protected]>
Co-authored-by: scoootscooob <[email protected]>
Co-authored-by: ruochen <[email protected]>
Co-authored-by: Onur Solmaz <[email protected]>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Frank Yang <[email protected]>
Co-authored-by: artwalker <[email protected]>
Co-authored-by: RichardCao <[email protected]>
Co-authored-by: RichardCao <[email protected]>
Co-authored-by: liuyang <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
Co-authored-by: Matt Van Horn <[email protected]>
Co-authored-by: Penchan <[email protected]>
Co-authored-by: Penchan <[email protected]>
Co-authored-by: Julia Bush <[email protected]>
0x666c6f added a commit to 0x666c6f/openclaw that referenced this pull request Mar 26, 2026
* fix(ci:PLA-678): restore main release pipeline health

* fix(ci:PLA-678): harden auto-response token fallback

* fix(ci:PLA-678): pin setup-bun to published release

* test(ci:PLA-678): align slack thread session expectations
0x666c6f added a commit to 0x666c6f/openclaw that referenced this pull request Mar 26, 2026
* fix(ci:PLA-678): restore main release pipeline health

* fix(ci:PLA-678): harden auto-response token fallback

* fix(ci:PLA-678): pin setup-bun to published release

* test(ci:PLA-678): align slack thread session expectations
0x666c6f added a commit to 0x666c6f/openclaw that referenced this pull request Mar 26, 2026
…nclaw#29)

* Plugins/llm-task: migrate to scoped plugin-sdk imports

* Plugins/lobster: migrate to scoped plugin-sdk imports

* Plugins/matrix: migrate to scoped plugin-sdk imports

* Plugins/mattermost: migrate to scoped plugin-sdk imports

* Plugins/memory-core: migrate to scoped plugin-sdk imports

* Plugins/memory-lancedb: migrate to scoped plugin-sdk imports

* Plugins/minimax-portal-auth: migrate to scoped plugin-sdk imports

* Plugins/msteams: migrate to scoped plugin-sdk imports

* Plugins/nextcloud-talk: migrate to scoped plugin-sdk imports

* Plugins/nostr: migrate to scoped plugin-sdk imports

* Plugins/open-prose: migrate to scoped plugin-sdk imports

* Plugins/phone-control: migrate to scoped plugin-sdk imports

* Plugins/qwen-portal-auth: migrate to scoped plugin-sdk imports

* Plugins/synology-chat: migrate to scoped plugin-sdk imports

* Plugins/talk-voice: migrate to scoped plugin-sdk imports

* Plugins/test-utils: migrate to scoped plugin-sdk imports

* Plugins/thread-ownership: migrate to scoped plugin-sdk imports

* Plugins/tlon: migrate to scoped plugin-sdk imports

* Plugins/twitch: migrate to scoped plugin-sdk imports

* Plugins/voice-call: migrate to scoped plugin-sdk imports

* Plugins/whatsapp: migrate to scoped plugin-sdk imports

* Plugins/zalo: migrate to scoped plugin-sdk imports

* Plugins/zalouser: migrate to scoped plugin-sdk imports

* Chore: remove accidental .DS_Store artifact

* chore(docs): add plugins refactor changelog entry

* feat(ios): add Live Activity connection status + stale cleanup (#33591)

* feat(ios): add live activity connection status and cleanup

Add lock-screen/Dynamic Island connection health states and prune duplicate/stale activities before reuse. This intentionally excludes AI/title generation and heavier UX rewrites from #27488.

Co-authored-by: leepokai <[email protected]>

* fix(ios): treat ended live activities as inactive

* chore(changelog): add PR reference and author thanks

---------

Co-authored-by: leepokai <[email protected]>

* fix: kill stuck ACP child processes on startup and harden sessions in discord threads (#33699)

* Gateway: resolve agent.wait for chat.send runs

* Discord: harden ACP thread binding + listener timeout

* ACPX: handle already-exited child wait

* Gateway/Discord: address PR review findings

* Discord: keep ACP error-state thread bindings on startup

* gateway: make agent.wait dedupe bridge event-driven

* discord: harden ACP probe classification and cap startup fan-out

* discord: add cooperative timeout cancellation

* discord: fix startup probe concurrency helper typing

* plugin-sdk: avoid Windows root-alias shard timeout

* plugin-sdk: keep root alias reflection path non-blocking

* discord+gateway: resolve remaining PR review findings

* gateway+discord: fix codex review regressions

* Discord/Gateway: address Codex review findings

* Gateway: keep agent.wait lifecycle active with shared run IDs

* Discord: clean up status reactions on aborted runs

* fix: add changelog note for ACP/Discord startup hardening (#33699) (thanks @dutifulbob)

---------

Co-authored-by: Onur <[email protected]>

* fix: relay ACP sessions_spawn parent streaming (#34310) (thanks @vincentkoc) (#34310)

Co-authored-by: Onur Solmaz <[email protected]>

* fix(telegram): materialize dm draft final to avoid duplicates

* docs(changelog): credit @Brotherinlaw-13 for #34318

* fix: prevent nodes media base64 context bloat (#34332)

* fix: preserve raw media invoke for HTTP tool clients (#34365)

* fix(slack): route system events to bound agent sessions (#34045)

* fix(slack): route system events via binding-aware session keys

* fix(slack): pass sender to system event session resolver

* fix(slack): include sender context for interaction session routing

* fix(slack): include modal submitter in session routing

* test(slack): cover binding-aware system event routing

* test(slack): update interaction session key assertions

* test(slack): assert reaction session routing carries sender

* docs(changelog): note slack system event routing fix

* Update CHANGELOG.md

* Delete changelog/fragments directory

* fix(memory): serialize local embedding initialization to avoid duplicate model loads (#15639)

Merged via squash.

Prepared head SHA: a085fc21a8ba7163fffdb5de640dd4dc1ff5a88e
Co-authored-by: SubtleSpark <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(model): propagate custom provider headers to model objects (#27490)

Merged via squash.

Prepared head SHA: e4183b398fc7eb4c18b2b691cb0dd882ec993608
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(daemon): handle systemctl is-enabled exit 4 (not-found) on Ubuntu (#33634)

Merged via squash.

Prepared head SHA: 67dffc3ee239cd7b813cb200c3dd5475d9e203a6
Co-authored-by: Yuandiaodiaodiao <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(node-host): sync rawCommand with hardened argv after executable path pinning (#33137)

Merged via squash.

Prepared head SHA: a7987905f7ad6cf5fee286ffa81ceaad8297174f
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* Agents: add generic poll-vote action support

* fix(ollama): pass provider headers to Ollama stream function (#24285)

createOllamaStreamFn() only accepted baseUrl, ignoring custom headers
configured in models.providers.<provider>.headers. This caused 403
errors when Ollama endpoints are behind reverse proxies that require
auth headers (e.g. X-OLLAMA-KEY via HAProxy).

Add optional defaultHeaders parameter to createOllamaStreamFn() and
merge them into every fetch request. Provider headers from config are
now passed through at the call site in the embedded runner.

Fixes #24285

* test(ollama): add default header precedence coverage

* chore(changelog): add PR entry openclaw#24337 thanks @echoVic

* Outbound: allow text-only plugin adapters

* Outbound: avoid empty multi-media fallback sends

* chore(changelog): align outbound adapter entry openclaw#32788 thanks @liuxiaopai-ai

* fix(outbound): fail media-only text-only adapter fallback

* chore(changelog): clarify outbound media-only fallback openclaw#32788 thanks @liuxiaopai-ai

* fix(review): enforce behavioral sweep validation

* Fix gateway restart false timeouts on Debian/systemd (#34874)

* daemon(systemd): target sudo caller user scope

* test(systemd): cover sudo user scope commands

* infra(ports): fall back to ss when lsof missing

* test(ports): verify ss fallback listener detection

* cli(gateway): use probe fallback for restart health

* test(gateway): cover restart-health probe fallback

* Compaction/Safeguard: require structured summary headings (#25555)

Merged via squash.

Prepared head SHA: 0b1df34806a7b788261290be55760fd89220de53
Co-authored-by: rodrigouroz <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Fix Linux daemon install checks when systemd user bus env is missing (#34884)

* daemon(systemd): fall back to machine user scope when user bus is missing

* test(systemd): cover machine scope fallback for user-bus errors

* test(systemd): reset execFile mock state across cases

* test(systemd): make machine-user fallback assertion portable

* fix(daemon): keep root sudo path on direct user scope

* test(systemd): cover sudo root user-scope behavior

* ci: use resolvable bun version in setup-node-env

* agents: preserve totalTokens on request failure instead of using contextWindow (#34275)

Merged via squash.

Prepared head SHA: f9d111d0a79a07815d476356e98a28df3a0000ba
Co-authored-by: RealKai42 <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix: align AGENTS.md template section names with post-compaction extraction (#25029) (#25098)

Merged via squash.

Prepared head SHA: 8cd6cc8049aab5a94d8a9d5fb08f2e792c4ac5fd
Co-authored-by: echoVic <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Changelog: add daemon systemd user-bus fallback entry (#34884)

* Changelog: add gateway restart health entry (#34874)

* fix: finalize spanish locale support

* fix: add spanish locale support (#35038) (thanks @DaoPromociones)

* fix(deps): patch hono transitive audit vulnerabilities

* fix(security): avoid prototype-chain account path checks (#34982)

Merged via squash.

Prepared head SHA: f89cc6a649959997fe1dec1e1c1bff9a61b2de98
Co-authored-by: HOYALIM <[email protected]>
Co-authored-by: dvrshil <[email protected]>
Reviewed-by: @dvrshil

* fix(deps): bump tar to 7.5.10

* docs(changelog): document dependency security fixes

* fix: restore auto-reply system events timeline (#34794) (thanks @anisoptera) (#34794)

Co-authored-by: Ayaan Zaidi <[email protected]>

* fix(feishu): comprehensive reply mechanism — outbound replyToId forwarding + topic-aware reply targeting (#33789)

* fix(feishu): comprehensive reply mechanism fix — outbound replyToId forwarding + topic-aware reply targeting

- Forward replyToId from ChannelOutboundContext through sendText/sendMedia
  to sendMessageFeishu/sendMarkdownCardFeishu/sendMediaFeishu, enabling
  reply-to-message via the message tool.

- Fix group reply targeting: use ctx.messageId (triggering message) in
  normal groups to prevent silent topic thread creation (#32980). Preserve
  ctx.rootId targeting for topic-mode groups (group_topic/group_topic_sender)
  and groups with explicit replyInThread config.

- Add regression tests for both fixes.

Fixes #32980
Fixes #32958
Related #19784

* fix: normalize Feishu delivery.to before comparing with messaging tool targets

- Add normalizeDeliveryTarget helper to strip user:/chat: prefixes for Feishu
- Apply normalization in matchesMessagingToolDeliveryTarget before comparison
- This ensures cron duplicate suppression works when session uses prefixed targets
  (user:ou_xxx) but messaging tool extract uses normalized bare IDs (ou_xxx)

Fixes review comment on PR #32755

(cherry picked from commit fc20106f16ccc88a5f02e58922bb7b7999fe9dcd)

* fix(feishu): catch thrown SDK errors for withdrawn reply targets

The Feishu Lark SDK can throw exceptions (SDK errors with .code or
AxiosErrors with .response.data.code) for withdrawn/deleted reply
targets, in addition to returning error codes in the response object.

Wrap reply calls in sendMessageFeishu and sendCardFeishu with
try-catch to handle thrown withdrawn/not-found errors (230011,
231003) and fall back to client.im.message.create, matching the
existing response-level fallback behavior.

Also extract sendFallbackDirect helper to deduplicate the
direct-send fallback block across both functions.

Closes #33496

(cherry picked from commit ad0901aec103a2c52f186686cfaf5f8ba54b4a48)

* feishu: forward outbound reply target context

(cherry picked from commit c129a691fcf552a1cebe1e8a22ea8611ffc3b377)

* feishu extension: tighten reply target fallback semantics

(cherry picked from commit f85ec610f267020b66713c09e648ec004b2e26f1)

* fix(feishu): align synthesized fallback typing and changelog attribution

* test(feishu): cover group_topic_sender reply targeting

---------

Co-authored-by: Xu Zimo <[email protected]>
Co-authored-by: Munem Hashmi <[email protected]>
Co-authored-by: bmendonca3 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(feishu): use msg_type media for mp4 video (fixes #33674) (#33720)

* fix(feishu): use msg_type media for mp4 video (fixes #33674)

* Feishu: harden streaming merge semantics and final reply dedupe

Use explicit streaming update semantics in the Feishu reply dispatcher:
treat onPartialReply payloads as snapshot updates and block fallback payloads
as delta chunks, then merge final text with the shared overlap-aware
mergeStreamingText helper before closing the stream.

Prevent duplicate final text delivery within the same dispatch cycle, and add
regression tests covering overlap snapshot merge, duplicate final suppression,
and block-as-delta behavior to guard against repeated/truncated output.

* fix(feishu): prefer message.reply for streaming cards in topic threads

* fix: reduce Feishu streaming card print_step to avoid duplicate rendering

Fixes openclaw/openclaw#33751

* Feishu: preserve media sends on duplicate finals and add media synthesis changelog

* Feishu: only dedupe exact duplicate final replies

* Feishu: use scoped plugin-sdk import in streaming-card tests

---------

Co-authored-by: 倪汉杰0668001185 <[email protected]>
Co-authored-by: zhengquanliu <[email protected]>
Co-authored-by: nick <[email protected]>
Co-authored-by: linhey <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(agents): bypass pendingDescendantRuns guard for cron announce delivery (#35185)

* fix(agents): bypass pendingDescendantRuns guard for cron announce delivery

Standalone cron job completions were blocked from direct channel delivery
when the cron run had spawned subagents that were still registered as
pending. The pendingDescendantRuns guard exists for live orchestration
coordination and should not apply to fire-and-forget cron announce sends.

Thread the announceType through the delivery chain and skip both the
child-descendant and requester-descendant pending-run guards when the
announce originates from a cron job.

Closes #34966

* fix: ensure outbound session entry for cron announce with named agents (#32432)

Named agents may not have a session entry for their delivery target,
causing the announce flow to silently fail (delivered=false, no error).

Two fixes:
1. Call ensureOutboundSessionEntry when resolving the cron announce
   session key so downstream delivery can find channel metadata.
2. Fall back to direct outbound delivery when announce delivery fails
   to ensure cron output reaches the target channel.

Closes #32432

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: guard announce direct-delivery fallback against suppression leaks (#32432)

The `!delivered` fallback condition was too broad — it caught intentional
suppressions (active subagents, interim messages, SILENT_REPLY_TOKEN) in
addition to actual announce delivery failures.  Add an
`announceDeliveryWasAttempted` flag so the direct-delivery fallback only
fires when `runSubagentAnnounceFlow` was actually called and failed.

Also remove the redundant `if (route)` guard in
`resolveCronAnnounceSessionKey` since `resolved` being truthy guarantees
`route` is non-null.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix(cron): harden announce synthesis follow-ups

---------

Co-authored-by: scoootscooob <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* Feishu: harden streaming merge semantics and final reply dedupe (#33245)

* Feishu: close duplicate final gap and cover routing precedence

* Feishu: resolve reviewer duplicate-final and routing feedback

* Feishu: tighten streaming send-mode option typing

* Feishu: fix reverse-overlap streaming merge ordering

* Feishu: align streaming final dedupe test expectation

* Feishu: allow distinct streaming finals while deduping repeats

---------

Co-authored-by: Tak Hoffman <[email protected]>

* fix: cron backup should preserve pre-edit snapshot (#35195) (#35234)

* fix(cron): avoid overwriting .bak during normalization

Fixes openclaw/openclaw#35195

* test(cron): preserve pre-edit bak snapshot in normalization path

---------

Co-authored-by: 0xsline <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(cron): stabilize restart catch-up replay semantics (#35351)

* Cron: stabilize restart catch-up replay semantics

* Cron: respect backoff in startup missed-run replay

* cron: narrow startup replay backoff guard (#35391)

* cron: unify stale-run recovery and preserve manual-run every anchors (#35363)

* cron: unify stale-run recovery and preserve manual every anchors

* cron: address unresolved review threads on recovery paths

* cron: remove duplicate timestamp helper after rebase

* refactor(telegram): remove unused webhook callback helper (#27816)

* fix(pr): make review claim step required

* fix(skills): deduplicate slash commands by skillName across all interfaces

Move skill-command deduplication by skillName from the Discord-only
`dedupeSkillCommandsForDiscord` into `listSkillCommandsForAgents` so
every interface (TUI, Slack, text) consistently sees a clean command
list without platform-specific workarounds.

When multiple agents share a skill with the same name the old code
emitted `github` + `github_2` and relied on Discord to collapse them.
Now `listSkillCommandsForAgents` returns only the first registration
per skillName, and the Discord-specific wrapper is removed.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* style: fix formatting in skill-commands.test.ts and provider.ts

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* style(skills): align formatting cleanup for dedupe changes

* chore(changelog): add dedupe note openclaw#27521 thanks @shivama205

* fix(agents): detect Venice provider proxying xAI/Grok models for schema cleaning (#35355)

Merged via squash.

Prepared head SHA: 8bfdec257bb6a6025cb69a0a213a433da32b15db
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(agents): decode HTML entities in xAI/Grok tool call arguments (#35276)

Merged via squash.

Prepared head SHA: c4445d2938898ded9c046614f9315dbda65ec573
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(agents): guard promoteThinkingTagsToBlocks against malformed content entries (#35143)

Merged via squash.

Prepared head SHA: 3971122f5fd27c66c8c9c5ce783f00e113b1f47b
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(web-ui): render Accounts schema node properly (#35380)

Co-authored-by: stakeswky <[email protected]>
Co-authored-by: liuxiaopai-ai <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(agents): guard context pruning against malformed thinking blocks (#35146)

Merged via squash.

Prepared head SHA: a196a565b1b8e806ffbf85172bcf1128796b45a2
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(gateway): prevent internal route leakage in chat.send

Synthesis of routing fixes from #35321, #34635, and #35356 for internal-client reply safety.

- Require explicit `deliver: true` before inheriting any external delivery route.
- Keep webchat/TUI/UI-origin traffic on internal routing by default.
- Allow configured-main session inheritance only for non-Webchat/UI clients, and honor `session.mainKey`.
- Add regression tests for UI no-inherit, configured-main CLI inherit, and deliver-flag behavior.

Co-authored-by: alexyyyander <[email protected]>
Co-authored-by: Octane0411 <[email protected]>
Co-authored-by: Linux2010 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(gateway): pass actual version to Control UI client instead of dev (#35230)

* fix(gateway): pass actual version to Control UI client instead of "dev"

The GatewayClient, CLI WS client, and browser Control UI all sent
"dev" as their clientVersion during handshake, making it impossible
to distinguish builds in gateway logs and health snapshots.

- GatewayClient and CLI WS client now use the resolved VERSION constant
- Control UI reads serverVersion from the bootstrap endpoint and
  forwards it when connecting
- Bootstrap contract extended with serverVersion field

Closes #35209

* Gateway: fix control-ui version version-reporting consistency

* Control UI: guard deferred bootstrap connect after disconnect

* fix(ui): accept same-origin http and relative gateway URLs for client version

---------

Co-authored-by: Tak Hoffman <[email protected]>

* chore(pr): enforce changelog placement and reduce merge sync churn

* TTS: add baseUrl support to OpenAI TTS config (#34321)

Merged via squash.

Prepared head SHA: e9a10cf81d2021cf81091dfa81e13ffdbb6a540a
Co-authored-by: RealKai42 <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* ACP: add persistent Discord channel and Telegram topic bindings (#34873)

* docs: add ACP persistent binding experiment plan

* docs: align ACP persistent binding spec to channel-local config

* docs: scope Telegram ACP bindings to forum topics only

* docs: lock bound /new and /reset behavior to in-place ACP reset

* ACP: add persistent discord/telegram conversation bindings

* ACP: fix persistent binding reuse and discord thread parent context

* docs: document channel-specific persistent ACP bindings

* ACP: split persistent bindings and share conversation id helpers

* ACP: defer configured binding init until preflight passes

* ACP: fix discord thread parent fallback and explicit disable inheritance

* ACP: keep bound /new and /reset in-place

* ACP: honor configured bindings in native command flows

* ACP: avoid configured fallback after runtime bind failure

* docs: refine ACP bindings experiment config examples

* acp: cut over to typed top-level persistent bindings

* ACP bindings: harden reset recovery and native command auth

* Docs: add ACP bound command auth proposal

* Tests: normalize i18n registry zh-CN assertion encoding

* ACP bindings: address review findings for reset and fallback routing

* ACP reset: gate hooks on success and preserve /new arguments

* ACP bindings: fix auth and binding-priority review findings

* Telegram ACP: gate ensure on auth and accepted messages

* ACP bindings: fix session-key precedence and unavailable handling

* ACP reset/native commands: honor fallback targets and abort on bootstrap failure

* Config schema: validate ACP binding channel and Telegram topic IDs

* Discord ACP: apply configured DM bindings to native commands

* ACP reset tails: dispatch through ACP after command handling

* ACP tails/native reset auth: fix target dispatch and restore full auth

* ACP reset detection: fallback to active ACP keys for DM contexts

* Tests: type runTurn mock input in ACP dispatch test

* ACP: dedup binding route bootstrap and reset target resolution

* reply: align ACP reset hooks with bound session key

* docs: replace personal discord ids with placeholders

* fix: add changelog entry for ACP persistent bindings (#34873) (thanks @dutifulbob)

---------

Co-authored-by: Onur <[email protected]>

* docs(telegram): recommend allowlist for single-user DM policy (#34841)

* docs(telegram): recommend allowlist for single-user bots

* docs(telegram): condense single-user allowlist note

---------

Co-authored-by: echoVic <[email protected]>

* fix(feishu): check response.ok before calling response.json() in streaming card (#35628)

Merged via squash.

Prepared head SHA: 62c3fec80d97cea9be344c0bef5358a0a5dc5560
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Mattermost: honor onmessage mention override and add gating diagnostics tests (#27160)

Merged via squash.

Prepared head SHA: 6cefb1d5bf3d6dfcec36c1cee3f9ea887f10c890
Co-authored-by: turian <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm

* fix(subagents): strip leaked [[reply_to]] tags from completion announces (#34503)

* fix(subagents): strip reply tags from completion delivery text

* test(subagents): cover reply-tag stripping in cron completion sends

* changelog: note iMessage reply-tag stripping in completion announces

* Update CHANGELOG.md

* Apply suggestion from @greptile-apps[bot]

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix(cron): restore direct fallback after announce failure in best-effort mode (openclaw#36177)

Verified:
- pnpm build
- pnpm check (fails on pre-existing origin/main lint debt in extensions/mattermost imports)
- pnpm test:macmini

Co-authored-by: Tak Hoffman <[email protected]>

* test(cron): add cross-channel announce fallback regression coverage (openclaw#36197)

Verified:
- pnpm install --frozen-lockfile
- pnpm build
- pnpm check (fails on pre-existing origin/main lint debt in extensions/mattermost imports)
- pnpm test:macmini

Co-authored-by: Tak Hoffman <[email protected]>

* feat(mattermost): add interactive buttons support (#19957)

Merged via squash.

Prepared head SHA: 8a25e608729d0b9fd07bb0ee4219d199d9796dbe
Co-authored-by: tonydehnke <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm

* fix(browser): remove deprecated --disable-blink-features=AutomationControlled flag

- Removes OpenClaw's default `--disable-blink-features=AutomationControlled` Chrome launch switch to avoid unsupported-flag warnings in newer Chrome (#35721).
- Preserves compatibility for older Chrome via `browser.extraArgs` override behavior (source analysis: #35770, #35728, #35727, #35885).
- Synthesis attribution: thanks @Sid-Qin, @kevinWangSheng, @ningding97, @Naylenv, @clawbie.

Source PR refs: #35734, #35770, #35728, #35727, #35885

Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: kevinWangSheng <[email protected]>
Co-authored-by: ningding97 <[email protected]>
Co-authored-by: Naylenv <[email protected]>
Co-authored-by: clawbie <[email protected]>
Co-authored-by: Takhoffman <[email protected]>

* fix(feishu): add HTTP timeout to prevent per-chat queue deadlocks (#36430)

When the Feishu API hangs or responds slowly, the sendChain never settles,
causing the per-chat queue to remain in a processing state forever and
blocking all subsequent messages in that thread. This adds a 30-second
default timeout to all Feishu HTTP requests by providing a timeout-aware
httpInstance to the Lark SDK client.

Closes #36412

Co-authored-by: Ayane <[email protected]>

* fix(feishu): use probed botName for mention checks (#36391)

* Feishu: honor bot mentions by ID despite aliases (Fixes #36317) (#36333)

* Mattermost: switch plugin-sdk imports to scoped subpaths (openclaw#36480)

Verified:
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: Takhoffman <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(feishu): accept groupPolicy "allowall" as alias for "open" (#36358)

* fix(feishu): accept groupPolicy "allowall" as alias for "open"

When users configure groupPolicy: "allowall" in Feishu channel config,
the Zod schema rejects the value and the runtime policy check falls
through to the allowlist path.  With an empty allowFrom array, all group
messages are silently dropped despite the intended "allow all" semantics.

Accept "allowall" at the schema level (transform to "open") and add a
runtime guard in isFeishuGroupAllowed so the value is handled even if it
bypasses schema validation.

Closes #36312

Made-with: Cursor

* Feishu: tighten allowall alias handling and coverage

---------

Co-authored-by: Tak Hoffman <[email protected]>

* synthesis: fix Feishu group mention slash parsing

## Summary\n\nFeishu group slash command parsing is fixed for mentions and command probes across authorization paths.\n\nThis includes:\n- Normalizing bot mention text in group context for reliable slash detection in message parsing.\n- Adding command-probe normalization for group slash invocations.\n\nCo-authored-by: Sid Qin <[email protected]>\nCo-authored-by: Tak Hoffman <[email protected]>

* Feishu: normalize group slash command probing

- Feishu/group slash command detection: normalize group mention wrappers before command-authorization probing so mention-prefixed commands are recognized in group routing.\n- Source PR: #36011\n- Contributor: @liuxiaopai-ai\n\nCo-authored-by: Tak Hoffman <[email protected]>\nCo-authored-by: liuxiaopai-ai <[email protected]>

* add prependSystemContext and appendSystemContext to before_prompt_build (fixes #35131) (#35177)

Merged via squash.

Prepared head SHA: d9a2869ad69db9449336a2e2846bd9de0e647ac6
Co-authored-by: maweibin <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(feishu): avoid media regressions from global HTTP timeout (#36500)

* fix(feishu): avoid media regressions from global http timeout

* fix(feishu): source HTTP timeout from config

* fix(feishu): apply media timeout override to image uploads

* fix(feishu): invalidate cached client when timeout changes

* fix(feishu): clamp timeout values and cover image download

* Gateway: add SecretRef support for gateway.auth.token with auth-mode guardrails (#35094)

* fix(embedded): classify model_context_window_exceeded as context overflow, trigger compaction (#35934)

Merged via squash.

Prepared head SHA: 20fa77289c80b2807a6779a3df70440242bc18ca
Co-authored-by: RealKai42 <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(agents): skip compaction API call when session has no real messages (#36451)

Merged via squash.

Prepared head SHA: 52dd6317895c7bd10855d2bd7dbbfc2f5279b68e
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(ui): catch marked.js parse errors to prevent Control UI crash (#36445)

- Prevent Control UI session render crashes when `marked.parse()` encounters pathological recursive markdown by safely falling back to escaped `<pre>` output.
- Tighten markdown fallback regression coverage and keep changelog attribution in sync for this crash-hardening path.

Co-authored-by: Bin Deng <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(session): archive old transcript on daily/scheduled reset to prevent orphaned files (#35493)

Merged via squash.

Prepared head SHA: 0d95549d752adecfc0b08d5cd55a8b8c75e264fe
Co-authored-by: byungsker <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(agents): set preserveSignatures to isAnthropic in resolveTranscriptPolicy (#32813)

Merged via squash.

Prepared head SHA: f522d21ca59a42abac554435a0aa646f6a34698d
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix: avoid false global rate-limit classification from generic cooldown text (#32972)

Merged via squash.

Prepared head SHA: 813c16f5afce415da130a917d9ce9f968912b477
Co-authored-by: stakeswky <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* refactor(agents): share failover HTTP status classification (#36615)

* fix(agents): classify transient failover statuses consistently

* fix(agents): preserve legacy failover status mapping

* fix(failover): narrow service-unavailable to require overload indicator (#32828) (#36646)

Merged via squash.

Prepared head SHA: 46fb4306127972d7635f371fd9029fbb9baff236
Co-authored-by: jnMetaCode <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* Compaction/Safeguard: add summary quality audit retries (#25556)

Merged via squash.

Prepared head SHA: be473efd1635616ebbae6e649d542ed50b4a827f
Co-authored-by: rodrigouroz <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* test(agents): add provider-backed failover regressions (#36735)

* test(agents): add provider-backed failover fixtures

* test(agents): cover more provider error docs

* test(agents): tighten provider doc fixtures

* Docs: add Slack typing reaction fallback

* Docs: update gateway config reference for Slack and TTS

* Docs: clarify OpenAI-compatible TTS endpoints

* Docs: document Control UI locale support

* Docs: cover heartbeat, cron, and plugin route updates

* fix(ui): bump dompurify to 3.3.2 (#36781)

* UI: bump dompurify to 3.3.2

* Deps: refresh dompurify lockfile

* UI: hoist lifecycle connect test mocks (#36788)

* fix(agents): classify insufficient_quota 400s as billing (#36783)

* feat: append UTC time alongside local time in shared Current time lines (#32423)

Merged via squash.

Prepared head SHA: 9e8ec13933b5317e7cff3f0bc048de515826c31a
Co-authored-by: jriff <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix(auth): grant senderIsOwner for internal channels with operator.admin scope (openclaw#35704)

Verified:
- pnpm install --frozen-lockfile
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: Naylenv <[email protected]>
Co-authored-by: Octane0411 <[email protected]>
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(config): prevent RangeError in merged schema cache key generation

Fix merged schema cache key generation for high-cardinality plugin/channel metadata by hashing incrementally instead of serializing one large aggregate string.

Includes changelog entry for the user-visible regression fix.

Co-authored-by: Tak Hoffman <[email protected]>
Co-authored-by: Bill <[email protected]>

* fix(slack): propagate mediaLocalRoots through Slack send path

Restore Slack local file upload parity with CVE-era local media allowlist enforcement by threading `mediaLocalRoots` through the Slack send call chain.

- pass `ctx.mediaLocalRoots` from Slack channel action adapter into `handleSlackAction`
- add and forward `mediaLocalRoots` in Slack action context/send path
- pass `mediaLocalRoots` into `sendMessageSlack` for upload allowlist enforcement
- add changelog entry with attribution for this behavior fix

Co-authored-by: 2233admin <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(slack): preserve dedupe while recovering dropped app_mention (#34937)

This PR fixes Slack mention loss without reintroducing duplicate dispatches.

- Preserve seen-message dedupe at ingress to prevent duplicate processing.
- Allow a one-time app_mention retry only when the paired message event was previously dropped before dispatch.
- Add targeted race tests for both recovery and duplicate-prevention paths.

Co-authored-by: littleben <[email protected]>
Co-authored-by: OpenClaw Agent <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* README: add algal to contributors list (#2046)

* fix: decouple Discord inbound worker timeout from listener timeout (#36602) (thanks @dutifulbob) (#36602)

Co-authored-by: Onur Solmaz <[email protected]>

* plugins: enforce prompt hook policy with runtime validation (#36567)

Merged via squash.

Prepared head SHA: 6b9d883b6ae33628235fb02ce39c0d0f46a065bb
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(memory): avoid destructive qmd collection rebinds

* Harden Telegram poll gating and schema consistency (#36547)

Merged via squash.

Prepared head SHA: f77824419e3d166f727474a9953a063a2b4547f2
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(browser): close tracked tabs on session cleanup (#36666)

* Diffs: restore system prompt guidance (#36904)

Merged via squash.

Prepared head SHA: 1b3be3c87957c068473d5c86b9efba4a1a8503f2
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(routing): avoid full binding rescans in resolveAgentRoute (#36915)

* fix(gateway): honor insecure ws override for remote hostnames

* fix(llm-task): load runEmbeddedPiAgent from dist/extensionAPI in installs

* fix(auth): harden openai-codex oauth login path

* feat(telegram/acp): Topic Binding, Pin Binding Message, Fix Spawn Param Parsing (#36683)

* fix(acp): normalize unicode flags and Telegram topic binding

* feat(telegram/acp): restore topic-bound ACP and session bindings

* fix(acpx): clarify permission-denied guidance

* feat(telegram/acp): pin spawn bind notice in topics

* docs(telegram): document ACP topic thread binding behavior

* refactor(reply): share Telegram conversation-id resolver

* fix(telegram/acp): preserve bound session routing semantics

* fix(telegram): respect binding persistence and expiry reporting

* refactor(telegram): simplify binding lifecycle persistence

* fix(telegram): bind acp spawns in direct messages

* fix: document telegram ACP topic binding changelog (#36683) (thanks @huntharo)

---------

Co-authored-by: Onur <[email protected]>

* fix(gateway): preserve streamed prefixes across tool boundaries

* fix(tui): prevent stale model indicator after /model

* Memory: handle SecretRef keys in doctor embeddings (#36835)

Merged via squash.

Prepared head SHA: c1a3d0caae60115d886e8bfc9983c9533c773f04
Co-authored-by: joshavant <[email protected]>
Co-authored-by: joshavant <[email protected]>
Reviewed-by: @joshavant

* fix(openai-codex): request required oauth api scopes (#24720)

* fix(memory-flush): ban timestamped variant files in default flush prompt (#34951)

Merged via squash.

Prepared head SHA: efadda4988b460e6da07be72994d4951d64239d0
Co-authored-by: zerone0x <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(tui): render final event error when assistant output is empty (#14687)

* feat(agents): flush reply pipeline before compaction wait (#35489)

Merged via squash.

Prepared head SHA: 7dbbcc510b74b0e8d35eb750d24575e34b5d769a
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(secrets): harden api key normalization for ByteString headers

* fix(slack): remove double mrkdwn conversion in native streaming path

Remove redundant text normalization from Slack native streaming markdown_text flow so Markdown formatting is preserved.

Synthesis context: overlaps reviewed from #34931, #34759, #34716, #34682, #34814.

Co-authored-by: littleben <[email protected]>
Co-authored-by: dunamismax <[email protected]>
Co-authored-by: Octane <[email protected]>
Co-authored-by: Mitsuyuki Osabe <[email protected]>
Co-authored-by: Kai <[email protected]>
Co-authored-by: OpenClaw Agent <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(kimi-coding): normalize anthropic tool payload format

* fix(slack): thread channel ID through inbound context for reactions (#34831)

Slack reaction/thread context routing fixes via canonical synthesis of #34831.

Co-authored-by: Tak <[email protected]>

* fix(heartbeat): pin HEARTBEAT.md reads to workspace path

* fix(subagents): recover announce cleanup after kill/complete race

* feat(hooks): emit compaction lifecycle hooks (#16788)

* fix(auth): harden openai-codex oauth refresh fallback

* fix(subagents): announce delivery with descendant gating, frozen result refresh, and cron retry (#35080)

Thanks @tyler6204

* fix(agents): avoid synthetic tool-result writes on idle-timeout cleanup

* fix(agent): harden undici stream timeouts for long openai-completions runs

* fix(slack): record app_mention retry key before dedupe check (#37033)

- Prime app_mention retry allowance before dedupe so near-simultaneous message/app_mention races do not drop valid mentions.
- Prevent duplicate dispatch when app_mention wins the race and message prepare later succeeds.
- Prune dispatched mention keys and add regression coverage for both dropped and successful in-flight message outcomes.

Co-authored-by: Tak Hoffman <[email protected]>

* fix(agents): honor explicit rate-limit cooldown probes in fallback runs

* fix(agents): allow configured ollama endpoints without dummy api keys

* fix(memory): recover qmd updates from duplicate document constraints

* Doctor: warn on implicit heartbeat directPolicy (#36789)

* Changelog: note heartbeat directPolicy doctor warning

* Tests: cover heartbeat directPolicy doctor warning

* Doctor: warn on implicit heartbeat directPolicy

* Tests: cover per-agent heartbeat directPolicy warning

* Update CHANGELOG.md

* Plugins: clarify registerHttpHandler migration errors (#36794)

* Changelog: note plugin HTTP route migration diagnostics

* Tests: cover registerHttpHandler migration diagnostics

* Plugins: clarify registerHttpHandler migration errors

* Tests: cover registerHttpHandler diagnostic edge cases

* Plugins: tighten registerHttpHandler migration hint

* fix(memory): repair qmd collection name conflicts during ensure

* fix(memory): handle qmd search results without docid

* Plugins: avoid false integrity drift prompts on unpinned updates (#37179)

* Plugins: skip drift prompts for unpinned updates

* Plugins: cover unpinned integrity update behavior

* Changelog: add #37179 release note

* Delete changelog/fragments directory

* Update CHANGELOG.md

* fix(whatsapp): remove implicit [openclaw] self-chat prefix

* fix: remove config.schema from agent gateway tool (#7382)

Merged via squash.

Prepared head SHA: f34a7780690a941936b31899e2d096b8a07f4afc
Co-authored-by: kakuteki <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* feat(openai): add gpt-5.4 support for API and Codex OAuth (#36590)

* feat(openai): add gpt-5.4 support and priority processing

* feat(openai-codex): add gpt-5.4 oauth support

* fix(openai): preserve provider overrides in gpt-5.4 fallback

* fix(openai-codex): keep xhigh for gpt-5.4 default

* fix(models): preserve configured overrides in list output

* fix(models): close gpt-5.4 integration gaps

* fix(openai): scope service tier to public api

* fix(openai): complete prep followups for gpt-5.4 support (#36590) (thanks @dorukardahan)

---------

Co-authored-by: Tyler Yust <[email protected]>

* fix(tui): preserve credential-like tokens in render sanitization

* CLI: make read-only SecretRef status flows degrade safely (#37023)

* CLI: add read-only SecretRef inspection

* CLI: fix read-only SecretRef status regressions

* CLI: preserve read-only SecretRef status fallbacks

* Docs: document read-only channel inspection hook

* CLI: preserve audit coverage for read-only SecretRefs

* CLI: fix read-only status account selection

* CLI: fix targeted gateway fallback analysis

* CLI: fix Slack HTTP read-only inspection

* CLI: align audit credential status checks

* CLI: restore Telegram read-only fallback semantics

* chore(changelog): update for #37023

Signed-off-by: joshavant <[email protected]>

* fix(agents): disable usage streaming chunks on non-native openai-completions

* feat(nano-banana-pro): add --aspect-ratio flag to generate_image.py (#28159)

* feat(nano-banana-pro): add --aspect-ratio flag to generate_image.py

* Nano Banana: allow all supported aspect ratios

* Docs: expand nano banana aspect ratio options

---------

Co-authored-by: Vincent Koc <[email protected]>

* fix(gateway): support image_url in OpenAI chat completions (#34068)

* fix(gateway): parse image_url in openai chat completions

* test(gateway): cover openai chat completions image_url flows

* docs(changelog): note openai image_url chat completions fix (#17685)

* fix(gateway): harden openai image_url parsing and limits

* test(gateway): add openai image_url regression coverage

* docs(changelog): expand #17685 openai chat completions note

* Gateway: make OpenAI image_url URL fetch opt-in and configurable

* Diagnostics: redact image base64 payload data in trace logs

* Changelog: note OpenAI image_url hardening follow-ups

* Gateway: enforce OpenAI image_url total budget incrementally

* Gateway: scope OpenAI image_url extraction to the active turn

* Update CHANGELOG.md

* fix(agents): avoid xAI web_search tool-name collisions

* fix: clear Telegram DM draft after materialize (#36746) (thanks @joelnishanth)

* Fix Control UI duplicate iMessage replies for internal webchat turns (#36151)

* Auto-reply: avoid routing external replies from internal webchat turns

* Auto-reply tests: cover internal webchat non-routing with external origin metadata

* Changelog: add Control UI iMessage duplicate-reply fix note

* Auto-reply context: track explicit deliver routes

* Gateway chat: mark explicit external deliver routes in context

* Auto-reply: preserve explicit deliver routes for internal webchat turns

* Auto-reply tests: cover explicit deliver routes from internal webchat turns

* Gateway chat tests: assert explicit deliver route context tagging

* fix: enforce 600 perms for cron store and run logs (#36078)

* fix: enforce secure permissions for cron store and run logs

* fix(cron): enforce dir perms and gate posix tests on windows

* Cron store tests: cover existing directory permission hardening

* Cron run-log tests: cover existing directory permission hardening

* Changelog: note cron file permission hardening

---------

Co-authored-by: linhey <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>

* fix(tui): accept canonical session-key aliases in chat event routing

* Gateway: normalize OpenAI stream chunk text

* Gateway: coerce chat deliverable route boolean

* fix(web_search): align brave language codes with API

* Respect source channel for agent event surfacing (#36030)

* fix(session): prefer webchat routes for direct ui turns (#37135)

* Gateway: discriminate input sources

* Cron: migrate legacy provider delivery hints

* Cron: stabilize runs-one-shot migration tests

* fix(memory): retry mcporter after Windows EINVAL spawn

* fix(onboarding): guard daemon status probe on headless linux

* Gateway: add path-scoped config schema lookup (#37266)

Merged via squash.

Prepared head SHA: 0c4d187f6fb66f2799d4047585d6368e433c883a
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* docs(changelog): add pr entry

* fix(ci): restore protocol and schema checks (#37470)

* Fix failover for zhipuai 1310 Weekly/Monthly Limit Exhausted (#33813)

Merged via squash.

Prepared head SHA: 3dc441e58de48913720cf7b6137fa761758d8344
Co-authored-by: zhouhe-xydt <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix(openai-codex-oauth): stop mutating authorize url scopes

* Update CHANGELOG.md

* fix(auth): remove bogus codex oauth responses probe

* docs(changelog): fold codex oauth fix notes

* docs(changelog): add codex oauth pr reference (#37558)

* fix(security:PLA-697): block local secret scratch files from commits

* feat: add dev EKS deployment for openclaw SRE container

* fix: stabilize slack socket mode in dev eks runtime

* fix(eks): reuse monitoring incident auth for openclaw-sre

* feat(deploy): add grafana env guards and prod deploy wrapper

* fix(security): redact tool outputs and enforce secret-safe runtime defaults

* feat(sre): harden heartbeat routing and enrich triage signals

* docs: add SRE hybrid intelligence design

Three-layer architecture to improve bot reasoning quality:
- Layer 1: Service knowledge (auto-discovery + overlays + incident memory)
- Layer 2: Multi-stage reasoning chain (triage → hypothesize → causal chain → action plan → cross-review)
- Layer 3: Incident learning loop (structured cards, overlay suggestions, feedback signals)

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* feat(sandbox): add boundary cli to common runtime image

* docs(sre): finalize hybrid intelligence design v19 after 18 Codex review rounds

Iteratively hardened the design through 18 adversarial Codex review rounds,
resolving 60+ findings (15+ CRITICAL, 45+ HIGH). Key fixes include:
- Decoupled incident_id (pre-Step11 immutable) from card_id (LLM-derived)
- Unified evidence/memory sanitization via shared _strip_instruction_tokens
- Fixed rerun interval default (3600s > heartbeat 1800s) to prevent every-cycle re-runs
- Added Phase 2 cross-review gap note and dual-column depth table
- Overlay suggestion idempotency via deterministic suggestion_key + upsert
- Decoupled chain timeout from legacy budget check
- Added predicate alignment docs for L3 pre-check vs L3 gate
- Adopted dynamic evidence_completeness denominator matching existing code
- Added scope note clarifying design vs current implementation

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* feat(sre): complete hybrid intelligence rollout and bot hardening

* fix(sre): harden slack reasoning, dual chain, and deploy auth/runtime

* ci: add ecr release pipeline and infra-helm image update trigger

* ci: switch workflows to github-hosted runners

* ci: allow manual ecr env target and use updater v4

* ci: remove windows jobs from workflow

* chore(pla-678): update fallback auth fixture and plan docs

* fix(pla-678): preserve control-ui host-header fallback in dev config

* refactor(pla-678): remove local sre chart and require infra-helm

* refactor(pla-678): remove direct eks deploy scripts

* ci(pla-678): remove labeler workflow

* ci(pla-678): refresh checks after disabling labeler

* build: install boundary CLI in SRE runtime image

* fix(slack:PLA-678): keep one thread lane across users

* fix(sre-skill): enforce live db-query runbook in dev seed

* fix(slack): ignore bot thread history when seeding new sessions

* fix(slack): force retry on repeated thread questions

* fix(sre-skill): require retry on repeated db requests

* docs(sre-skill): make retry policy generic across repeated asks

* fix(sre:PLA-678): enforce live linear ticket updates

* fix(sre:PLA-678): use [PLATFORM] Backlog linear project

* fix(sre:PLA-678): label linked linear tickets as openclaw-sre

* fix(sre:PLA-678): auto-label linked linear tickets for auto-pr

* test(sre:PLA-678): make tracking label test executable

* fix(slack:PLA-678): remove status-final completion banner (#16)

* fix(slack:PLA-678): enable direct file attachments from agent replies (#17)

* fix(slack:PLA-678): remove status-final completion banner

* fix(slack): enable direct file attachments from agent replies

* refactor(sre:PLA-678): remove local deploy config mirror (#18)

* fix: compact oversized auto-generated pr bodies

* fix(sre): add built-in linear incident memory provider

* feat(sre): add erpc helper with flo secret query

* fix(sre): enforce canonical rpc.morpho.dev erpc endpoint

* refactor(sre): remove local deploy config mirror

* fix(slack:PLA-678): force DM replies into per-message threads (#19)

* fix: compact oversized auto-generated pr bodies

* fix(sre): add built-in linear incident memory provider

* feat(sre): add erpc helper with flo secret query

* fix(sre): enforce canonical rpc.morpho.dev erpc endpoint

* refactor(sre): remove local deploy config mirror

* fix(slack): force threaded replies for direct messages

* feat(cron:PLA-678): use conversation history in self-improve runs (#20)

* fix(slack:PLA-678): improve progress update readability (#21)

* fix(ci:PLA-678): restore main release pipeline health (#22)

* fix(ci:PLA-678): restore main release pipeline health

* fix(ci:PLA-678): harden auto-response token fallback

* fix(ci:PLA-678): pin setup-bun to published release

* test(ci:PLA-678): align slack thread session expectations

* fix(sre:PLA-678): harden Slack reply delivery and image release flow (#23)

* fix(slack:PLA-678): harden thread-scoped reply delivery

* fix(slack:PLA-678): satisfy lint after rebase

* ci(release:PLA-678): move image release to cached ecr flow

* ci(release:PLA-678): use official docker build actions

* fix(slack:PLA-722): preserve progress updates during final-answer gating (#24)

* fix(sre:PLA-724): restore ECR runtime image toolchain (#25)

* fix(failover): classify HTTP 402 as rate_limit when payload indicates usage limit (#30484) (#36802)

* fix(failover): classify HTTP 402 as rate_limit when payload indicates usage limit (#30484)

Some providers (notably Anthropic Claude Max plan) surface temporary
usage/rate-limit failures as HTTP 402 instead of 429. Before this change,
all 402s were unconditionally mapped to 'billing', which produced a
misleading 'run out of credits' warning for Max plan users who simply
hit their usage window.

This follows the same pattern introduced for HTTP 400 in #36783: check
the error message for an explicit rate-limit signal before falling back
to the default status-code classification.

- classifyFailoverReasonFromHttpStatus now returns 'rate_limit' for 402
  when isRateLimitErrorMessage matches the payload text
- Added regression tests covering both the rate-limit and billing paths
  on 402

* fix: narrow 402 rate-limit matcher to prevent billing misclassification

The original implementation used isRateLimitErrorMessage(), which matches
phrases like 'quota exceeded' that legitimately appear in billing errors.

This commit replaces it with a narrow, 402-specific matcher that requires
BOTH retry language (try again/retry/temporary/cooldown) AND limit
terminology (usage limit/rate limit/organization usage).

Prevents misclassification of errors like:
'HTTP 402: exceeded quota, please add credits' -> billing (not rate_limit)

Added regression test for the ambiguous case.

---------

Co-authored-by: Val Alexander <[email protected]>

* fix(mattermost): allow reachable interaction callback URLs (#37543)

Merged via squash.

Prepared head SHA: 4d593731be5a5dcbf3106d596b38acfeb8cf0aa8
Co-authored-by: mukhtharcm <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm

---------

Signed-off-by: joshavant <[email protected]>
Co-authored-by: Gustavo Madeira Santana <[email protected]>
Co-authored-by: Mariano <[email protected]>
Co-authored-by: leepokai <[email protected]>
Co-authored-by: Bob <[email protected]>
Co-authored-by: Onur <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
Co-authored-by: huangcj <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: Sid <[email protected]>
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Co-authored-by: a <[email protected]>
Co-authored-by: echoVic <[email protected]>
Co-authored-by: Shakker <[email protected]>
Co-authored-by: liuxiaopai-ai <[email protected]>
Co-authored-by: Rodrigo Uroz <[email protected]>
Co-authored-by: rodrigouroz <[email protected]>
Co-authored-by: jalehman <[email protected]>
Co-authored-by: Kai <[email protected]>
Co-authored-by: RealKai42 <[email protected]>
Co-authored-by: 青雲 <[email protected]>
Co-authored-by: echoVic <[email protected]>
Co-authored-by: Darshil <[email protected]>
Co-authored-by: Ho Lim <[email protected]>
Co-authored-by: dvrshil <[email protected]>
Co-authored-by: Isis Anisoptera <[email protected]>
Co-authored-by: Madoka <[email protected]>
Co-authored-by: Xu Zimo <[email protected]>
Co-authored-by: Munem Hashmi <[email protected]>
Co-authored-by: bmendonca3 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>
Co-authored-by: Nhj <[email protected]>
Co-authored-by: 倪汉杰0668001185 <[email protected]>
Co-authored-by: zhengquanliu <[email protected]>
Co-authored-by: nick <[email protected]>
Co-authored-by: linhey <[email protected]>
Co-authored-by: scoootscooob <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: rexl2018 <[email protected]>
Co-authored-by: sline <[email protected]>
Co-authored-by: 0xsline <[email protected]>
Co-authored-by: Harold Hunt <[email protected]>
Co-authored-by: Shivam <[email protected]>
Co-authored-by: 不做了睡大觉 <[email protected]>
Co-authored-by: alexyyyander <[email protected]>
Co-authored-by: alexyyyander <[email protected]>
Co-authored-by: Octane0411 <[email protected]>
Co-authored-by: Linux2010 <[email protected]>
Co-authored-by: echoVic <[email protected]>
Co-authored-by: Joseph Turian <[email protected]>
Co-authored-by: turian <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Tony Dehnke <[email protected]>
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: kevinWangSheng <[email protected]>
Co-authored-by: ningding97 <[email protected]>
Co-authored-by: Naylenv <[email protected]>
Co-authored-by: clawbie <[email protected]>
Co-authored-by: Takhoffman <[email protected]>
Co-authored-by: Ayane <[email protected]>
Co-authored-by: Ayane <[email protected]>
Co-authored-by: StingNing <[email protected]>
Co-authored-by: maweibin <[email protected]>
Co-authored-by: maweibin <[email protected]>
Co-authored-by: Josh Avant <[email protected]>
Co-authored-by: Bin Deng <[email protected]>
Co-authored-by: Byungsker <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Co-authored-by: Altay <[email protected]>
Co-authored-by: jiangnan <[email protected]>
Co-authored-by: jnMetaCode <[email protected]>
Co-authored-by: Jacob Riff <[email protected]>
Co-authored-by: jriff <[email protected]>
Co-authored-by: Naylenv <[email protected]>
Co-authored-by: Bill <[email protected]>
Co-authored-by: 2233admin <[email protected]>
Co-authored-by: 2233admin <[email protected]>
Co-authored-by: littleben <[email protected]>
Co-authored-by: littleben <[email protected]>
Co-authored-by: OpenClaw Agent <[email protected]>
Co-authored-by: Vignesh Natarajan <[email protected]>
Co-authored-by: zerone0x <[email protected]>
Co-authored-by: zerone0x <[email protected]>
Co-authored-by: dunamismax <[email protected]>
Co-authored-by: Octane <[email protected]>
Co-authored-by: Mitsuyuki Osabe <[email protected]>
Co-authored-by: Tak <[email protected]>
Co-authored-by: Tyler Yust <[email protected]>
Co-authored-by: Hinata Kaga (samon) <[email protected]>
Co-authored-by: dorukardahan <[email protected]>
Co-authored-by: Tyler Yust <[email protected]>
Co-authored-by: Brenner Spear <[email protected]>
Co-authored-by: aerelune <[email protected]>
Co-authored-by: Frank Yang <[email protected]>
Co-authored-by: zhouhe-xydt <[email protected]>
Co-authored-by: zhouhe-xydt <[email protected]>
Co-authored-by: Vignesh <[email protected]>
Co-authored-by: OpenClaw SRE Bot <[email protected]>
Co-authored-by: Xinhua Gu <[email protected]>
Co-authored-by: Val Alexander <[email protected]>
0x666c6f added a commit to 0x666c6f/openclaw that referenced this pull request Mar 26, 2026
)

* Plugins/matrix: migrate to scoped plugin-sdk imports

* Plugins/mattermost: migrate to scoped plugin-sdk imports

* Plugins/memory-core: migrate to scoped plugin-sdk imports

* Plugins/memory-lancedb: migrate to scoped plugin-sdk imports

* Plugins/minimax-portal-auth: migrate to scoped plugin-sdk imports

* Plugins/msteams: migrate to scoped plugin-sdk imports

* Plugins/nextcloud-talk: migrate to scoped plugin-sdk imports

* Plugins/nostr: migrate to scoped plugin-sdk imports

* Plugins/open-prose: migrate to scoped plugin-sdk imports

* Plugins/phone-control: migrate to scoped plugin-sdk imports

* Plugins/qwen-portal-auth: migrate to scoped plugin-sdk imports

* Plugins/synology-chat: migrate to scoped plugin-sdk imports

* Plugins/talk-voice: migrate to scoped plugin-sdk imports

* Plugins/test-utils: migrate to scoped plugin-sdk imports

* Plugins/thread-ownership: migrate to scoped plugin-sdk imports

* Plugins/tlon: migrate to scoped plugin-sdk imports

* Plugins/twitch: migrate to scoped plugin-sdk imports

* Plugins/voice-call: migrate to scoped plugin-sdk imports

* Plugins/whatsapp: migrate to scoped plugin-sdk imports

* Plugins/zalo: migrate to scoped plugin-sdk imports

* Plugins/zalouser: migrate to scoped plugin-sdk imports

* Chore: remove accidental .DS_Store artifact

* chore(docs): add plugins refactor changelog entry

* feat(ios): add Live Activity connection status + stale cleanup (#33591)

* feat(ios): add live activity connection status and cleanup

Add lock-screen/Dynamic Island connection health states and prune duplicate/stale activities before reuse. This intentionally excludes AI/title generation and heavier UX rewrites from #27488.

Co-authored-by: leepokai <[email protected]>

* fix(ios): treat ended live activities as inactive

* chore(changelog): add PR reference and author thanks

---------

Co-authored-by: leepokai <[email protected]>

* fix: kill stuck ACP child processes on startup and harden sessions in discord threads (#33699)

* Gateway: resolve agent.wait for chat.send runs

* Discord: harden ACP thread binding + listener timeout

* ACPX: handle already-exited child wait

* Gateway/Discord: address PR review findings

* Discord: keep ACP error-state thread bindings on startup

* gateway: make agent.wait dedupe bridge event-driven

* discord: harden ACP probe classification and cap startup fan-out

* discord: add cooperative timeout cancellation

* discord: fix startup probe concurrency helper typing

* plugin-sdk: avoid Windows root-alias shard timeout

* plugin-sdk: keep root alias reflection path non-blocking

* discord+gateway: resolve remaining PR review findings

* gateway+discord: fix codex review regressions

* Discord/Gateway: address Codex review findings

* Gateway: keep agent.wait lifecycle active with shared run IDs

* Discord: clean up status reactions on aborted runs

* fix: add changelog note for ACP/Discord startup hardening (#33699) (thanks @dutifulbob)

---------

Co-authored-by: Onur <[email protected]>

* fix: relay ACP sessions_spawn parent streaming (#34310) (thanks @vincentkoc) (#34310)

Co-authored-by: Onur Solmaz <[email protected]>

* fix(telegram): materialize dm draft final to avoid duplicates

* docs(changelog): credit @Brotherinlaw-13 for #34318

* fix: prevent nodes media base64 context bloat (#34332)

* fix: preserve raw media invoke for HTTP tool clients (#34365)

* fix(slack): route system events to bound agent sessions (#34045)

* fix(slack): route system events via binding-aware session keys

* fix(slack): pass sender to system event session resolver

* fix(slack): include sender context for interaction session routing

* fix(slack): include modal submitter in session routing

* test(slack): cover binding-aware system event routing

* test(slack): update interaction session key assertions

* test(slack): assert reaction session routing carries sender

* docs(changelog): note slack system event routing fix

* Update CHANGELOG.md

* Delete changelog/fragments directory

* fix(memory): serialize local embedding initialization to avoid duplicate model loads (#15639)

Merged via squash.

Prepared head SHA: a085fc21a8ba7163fffdb5de640dd4dc1ff5a88e
Co-authored-by: SubtleSpark <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(model): propagate custom provider headers to model objects (#27490)

Merged via squash.

Prepared head SHA: e4183b398fc7eb4c18b2b691cb0dd882ec993608
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(daemon): handle systemctl is-enabled exit 4 (not-found) on Ubuntu (#33634)

Merged via squash.

Prepared head SHA: 67dffc3ee239cd7b813cb200c3dd5475d9e203a6
Co-authored-by: Yuandiaodiaodiao <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(node-host): sync rawCommand with hardened argv after executable path pinning (#33137)

Merged via squash.

Prepared head SHA: a7987905f7ad6cf5fee286ffa81ceaad8297174f
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* Agents: add generic poll-vote action support

* fix(ollama): pass provider headers to Ollama stream function (#24285)

createOllamaStreamFn() only accepted baseUrl, ignoring custom headers
configured in models.providers.<provider>.headers. This caused 403
errors when Ollama endpoints are behind reverse proxies that require
auth headers (e.g. X-OLLAMA-KEY via HAProxy).

Add optional defaultHeaders parameter to createOllamaStreamFn() and
merge them into every fetch request. Provider headers from config are
now passed through at the call site in the embedded runner.

Fixes #24285

* test(ollama): add default header precedence coverage

* chore(changelog): add PR entry openclaw#24337 thanks @echoVic

* Outbound: allow text-only plugin adapters

* Outbound: avoid empty multi-media fallback sends

* chore(changelog): align outbound adapter entry openclaw#32788 thanks @liuxiaopai-ai

* fix(outbound): fail media-only text-only adapter fallback

* chore(changelog): clarify outbound media-only fallback openclaw#32788 thanks @liuxiaopai-ai

* fix(review): enforce behavioral sweep validation

* Fix gateway restart false timeouts on Debian/systemd (#34874)

* daemon(systemd): target sudo caller user scope

* test(systemd): cover sudo user scope commands

* infra(ports): fall back to ss when lsof missing

* test(ports): verify ss fallback listener detection

* cli(gateway): use probe fallback for restart health

* test(gateway): cover restart-health probe fallback

* Compaction/Safeguard: require structured summary headings (#25555)

Merged via squash.

Prepared head SHA: 0b1df34806a7b788261290be55760fd89220de53
Co-authored-by: rodrigouroz <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Fix Linux daemon install checks when systemd user bus env is missing (#34884)

* daemon(systemd): fall back to machine user scope when user bus is missing

* test(systemd): cover machine scope fallback for user-bus errors

* test(systemd): reset execFile mock state across cases

* test(systemd): make machine-user fallback assertion portable

* fix(daemon): keep root sudo path on direct user scope

* test(systemd): cover sudo root user-scope behavior

* ci: use resolvable bun version in setup-node-env

* agents: preserve totalTokens on request failure instead of using contextWindow (#34275)

Merged via squash.

Prepared head SHA: f9d111d0a79a07815d476356e98a28df3a0000ba
Co-authored-by: RealKai42 <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix: align AGENTS.md template section names with post-compaction extraction (#25029) (#25098)

Merged via squash.

Prepared head SHA: 8cd6cc8049aab5a94d8a9d5fb08f2e792c4ac5fd
Co-authored-by: echoVic <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Changelog: add daemon systemd user-bus fallback entry (#34884)

* Changelog: add gateway restart health entry (#34874)

* fix: finalize spanish locale support

* fix: add spanish locale support (#35038) (thanks @DaoPromociones)

* fix(deps): patch hono transitive audit vulnerabilities

* fix(security): avoid prototype-chain account path checks (#34982)

Merged via squash.

Prepared head SHA: f89cc6a649959997fe1dec1e1c1bff9a61b2de98
Co-authored-by: HOYALIM <[email protected]>
Co-authored-by: dvrshil <[email protected]>
Reviewed-by: @dvrshil

* fix(deps): bump tar to 7.5.10

* docs(changelog): document dependency security fixes

* fix: restore auto-reply system events timeline (#34794) (thanks @anisoptera) (#34794)

Co-authored-by: Ayaan Zaidi <[email protected]>

* fix(feishu): comprehensive reply mechanism — outbound replyToId forwarding + topic-aware reply targeting (#33789)

* fix(feishu): comprehensive reply mechanism fix — outbound replyToId forwarding + topic-aware reply targeting

- Forward replyToId from ChannelOutboundContext through sendText/sendMedia
  to sendMessageFeishu/sendMarkdownCardFeishu/sendMediaFeishu, enabling
  reply-to-message via the message tool.

- Fix group reply targeting: use ctx.messageId (triggering message) in
  normal groups to prevent silent topic thread creation (#32980). Preserve
  ctx.rootId targeting for topic-mode groups (group_topic/group_topic_sender)
  and groups with explicit replyInThread config.

- Add regression tests for both fixes.

Fixes #32980
Fixes #32958
Related #19784

* fix: normalize Feishu delivery.to before comparing with messaging tool targets

- Add normalizeDeliveryTarget helper to strip user:/chat: prefixes for Feishu
- Apply normalization in matchesMessagingToolDeliveryTarget before comparison
- This ensures cron duplicate suppression works when session uses prefixed targets
  (user:ou_xxx) but messaging tool extract uses normalized bare IDs (ou_xxx)

Fixes review comment on PR #32755

(cherry picked from commit fc20106f16ccc88a5f02e58922bb7b7999fe9dcd)

* fix(feishu): catch thrown SDK errors for withdrawn reply targets

The Feishu Lark SDK can throw exceptions (SDK errors with .code or
AxiosErrors with .response.data.code) for withdrawn/deleted reply
targets, in addition to returning error codes in the response object.

Wrap reply calls in sendMessageFeishu and sendCardFeishu with
try-catch to handle thrown withdrawn/not-found errors (230011,
231003) and fall back to client.im.message.create, matching the
existing response-level fallback behavior.

Also extract sendFallbackDirect helper to deduplicate the
direct-send fallback block across both functions.

Closes #33496

(cherry picked from commit ad0901aec103a2c52f186686cfaf5f8ba54b4a48)

* feishu: forward outbound reply target context

(cherry picked from commit c129a691fcf552a1cebe1e8a22ea8611ffc3b377)

* feishu extension: tighten reply target fallback semantics

(cherry picked from commit f85ec610f267020b66713c09e648ec004b2e26f1)

* fix(feishu): align synthesized fallback typing and changelog attribution

* test(feishu): cover group_topic_sender reply targeting

---------

Co-authored-by: Xu Zimo <[email protected]>
Co-authored-by: Munem Hashmi <[email protected]>
Co-authored-by: bmendonca3 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(feishu): use msg_type media for mp4 video (fixes #33674) (#33720)

* fix(feishu): use msg_type media for mp4 video (fixes #33674)

* Feishu: harden streaming merge semantics and final reply dedupe

Use explicit streaming update semantics in the Feishu reply dispatcher:
treat onPartialReply payloads as snapshot updates and block fallback payloads
as delta chunks, then merge final text with the shared overlap-aware
mergeStreamingText helper before closing the stream.

Prevent duplicate final text delivery within the same dispatch cycle, and add
regression tests covering overlap snapshot merge, duplicate final suppression,
and block-as-delta behavior to guard against repeated/truncated output.

* fix(feishu): prefer message.reply for streaming cards in topic threads

* fix: reduce Feishu streaming card print_step to avoid duplicate rendering

Fixes openclaw/openclaw#33751

* Feishu: preserve media sends on duplicate finals and add media synthesis changelog

* Feishu: only dedupe exact duplicate final replies

* Feishu: use scoped plugin-sdk import in streaming-card tests

---------

Co-authored-by: 倪汉杰0668001185 <[email protected]>
Co-authored-by: zhengquanliu <[email protected]>
Co-authored-by: nick <[email protected]>
Co-authored-by: linhey <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(agents): bypass pendingDescendantRuns guard for cron announce delivery (#35185)

* fix(agents): bypass pendingDescendantRuns guard for cron announce delivery

Standalone cron job completions were blocked from direct channel delivery
when the cron run had spawned subagents that were still registered as
pending. The pendingDescendantRuns guard exists for live orchestration
coordination and should not apply to fire-and-forget cron announce sends.

Thread the announceType through the delivery chain and skip both the
child-descendant and requester-descendant pending-run guards when the
announce originates from a cron job.

Closes #34966

* fix: ensure outbound session entry for cron announce with named agents (#32432)

Named agents may not have a session entry for their delivery target,
causing the announce flow to silently fail (delivered=false, no error).

Two fixes:
1. Call ensureOutboundSessionEntry when resolving the cron announce
   session key so downstream delivery can find channel metadata.
2. Fall back to direct outbound delivery when announce delivery fails
   to ensure cron output reaches the target channel.

Closes #32432

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: guard announce direct-delivery fallback against suppression leaks (#32432)

The `!delivered` fallback condition was too broad — it caught intentional
suppressions (active subagents, interim messages, SILENT_REPLY_TOKEN) in
addition to actual announce delivery failures.  Add an
`announceDeliveryWasAttempted` flag so the direct-delivery fallback only
fires when `runSubagentAnnounceFlow` was actually called and failed.

Also remove the redundant `if (route)` guard in
`resolveCronAnnounceSessionKey` since `resolved` being truthy guarantees
`route` is non-null.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix(cron): harden announce synthesis follow-ups

---------

Co-authored-by: scoootscooob <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* Feishu: harden streaming merge semantics and final reply dedupe (#33245)

* Feishu: close duplicate final gap and cover routing precedence

* Feishu: resolve reviewer duplicate-final and routing feedback

* Feishu: tighten streaming send-mode option typing

* Feishu: fix reverse-overlap streaming merge ordering

* Feishu: align streaming final dedupe test expectation

* Feishu: allow distinct streaming finals while deduping repeats

---------

Co-authored-by: Tak Hoffman <[email protected]>

* fix: cron backup should preserve pre-edit snapshot (#35195) (#35234)

* fix(cron): avoid overwriting .bak during normalization

Fixes openclaw/openclaw#35195

* test(cron): preserve pre-edit bak snapshot in normalization path

---------

Co-authored-by: 0xsline <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(cron): stabilize restart catch-up replay semantics (#35351)

* Cron: stabilize restart catch-up replay semantics

* Cron: respect backoff in startup missed-run replay

* cron: narrow startup replay backoff guard (#35391)

* cron: unify stale-run recovery and preserve manual-run every anchors (#35363)

* cron: unify stale-run recovery and preserve manual every anchors

* cron: address unresolved review threads on recovery paths

* cron: remove duplicate timestamp helper after rebase

* refactor(telegram): remove unused webhook callback helper (#27816)

* fix(pr): make review claim step required

* fix(skills): deduplicate slash commands by skillName across all interfaces

Move skill-command deduplication by skillName from the Discord-only
`dedupeSkillCommandsForDiscord` into `listSkillCommandsForAgents` so
every interface (TUI, Slack, text) consistently sees a clean command
list without platform-specific workarounds.

When multiple agents share a skill with the same name the old code
emitted `github` + `github_2` and relied on Discord to collapse them.
Now `listSkillCommandsForAgents` returns only the first registration
per skillName, and the Discord-specific wrapper is removed.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* style: fix formatting in skill-commands.test.ts and provider.ts

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* style(skills): align formatting cleanup for dedupe changes

* chore(changelog): add dedupe note openclaw#27521 thanks @shivama205

* fix(agents): detect Venice provider proxying xAI/Grok models for schema cleaning (#35355)

Merged via squash.

Prepared head SHA: 8bfdec257bb6a6025cb69a0a213a433da32b15db
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(agents): decode HTML entities in xAI/Grok tool call arguments (#35276)

Merged via squash.

Prepared head SHA: c4445d2938898ded9c046614f9315dbda65ec573
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(agents): guard promoteThinkingTagsToBlocks against malformed content entries (#35143)

Merged via squash.

Prepared head SHA: 3971122f5fd27c66c8c9c5ce783f00e113b1f47b
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(web-ui): render Accounts schema node properly (#35380)

Co-authored-by: stakeswky <[email protected]>
Co-authored-by: liuxiaopai-ai <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(agents): guard context pruning against malformed thinking blocks (#35146)

Merged via squash.

Prepared head SHA: a196a565b1b8e806ffbf85172bcf1128796b45a2
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(gateway): prevent internal route leakage in chat.send

Synthesis of routing fixes from #35321, #34635, and #35356 for internal-client reply safety.

- Require explicit `deliver: true` before inheriting any external delivery route.
- Keep webchat/TUI/UI-origin traffic on internal routing by default.
- Allow configured-main session inheritance only for non-Webchat/UI clients, and honor `session.mainKey`.
- Add regression tests for UI no-inherit, configured-main CLI inherit, and deliver-flag behavior.

Co-authored-by: alexyyyander <[email protected]>
Co-authored-by: Octane0411 <[email protected]>
Co-authored-by: Linux2010 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(gateway): pass actual version to Control UI client instead of dev (#35230)

* fix(gateway): pass actual version to Control UI client instead of "dev"

The GatewayClient, CLI WS client, and browser Control UI all sent
"dev" as their clientVersion during handshake, making it impossible
to distinguish builds in gateway logs and health snapshots.

- GatewayClient and CLI WS client now use the resolved VERSION constant
- Control UI reads serverVersion from the bootstrap endpoint and
  forwards it when connecting
- Bootstrap contract extended with serverVersion field

Closes #35209

* Gateway: fix control-ui version version-reporting consistency

* Control UI: guard deferred bootstrap connect after disconnect

* fix(ui): accept same-origin http and relative gateway URLs for client version

---------

Co-authored-by: Tak Hoffman <[email protected]>

* chore(pr): enforce changelog placement and reduce merge sync churn

* TTS: add baseUrl support to OpenAI TTS config (#34321)

Merged via squash.

Prepared head SHA: e9a10cf81d2021cf81091dfa81e13ffdbb6a540a
Co-authored-by: RealKai42 <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* ACP: add persistent Discord channel and Telegram topic bindings (#34873)

* docs: add ACP persistent binding experiment plan

* docs: align ACP persistent binding spec to channel-local config

* docs: scope Telegram ACP bindings to forum topics only

* docs: lock bound /new and /reset behavior to in-place ACP reset

* ACP: add persistent discord/telegram conversation bindings

* ACP: fix persistent binding reuse and discord thread parent context

* docs: document channel-specific persistent ACP bindings

* ACP: split persistent bindings and share conversation id helpers

* ACP: defer configured binding init until preflight passes

* ACP: fix discord thread parent fallback and explicit disable inheritance

* ACP: keep bound /new and /reset in-place

* ACP: honor configured bindings in native command flows

* ACP: avoid configured fallback after runtime bind failure

* docs: refine ACP bindings experiment config examples

* acp: cut over to typed top-level persistent bindings

* ACP bindings: harden reset recovery and native command auth

* Docs: add ACP bound command auth proposal

* Tests: normalize i18n registry zh-CN assertion encoding

* ACP bindings: address review findings for reset and fallback routing

* ACP reset: gate hooks on success and preserve /new arguments

* ACP bindings: fix auth and binding-priority review findings

* Telegram ACP: gate ensure on auth and accepted messages

* ACP bindings: fix session-key precedence and unavailable handling

* ACP reset/native commands: honor fallback targets and abort on bootstrap failure

* Config schema: validate ACP binding channel and Telegram topic IDs

* Discord ACP: apply configured DM bindings to native commands

* ACP reset tails: dispatch through ACP after command handling

* ACP tails/native reset auth: fix target dispatch and restore full auth

* ACP reset detection: fallback to active ACP keys for DM contexts

* Tests: type runTurn mock input in ACP dispatch test

* ACP: dedup binding route bootstrap and reset target resolution

* reply: align ACP reset hooks with bound session key

* docs: replace personal discord ids with placeholders

* fix: add changelog entry for ACP persistent bindings (#34873) (thanks @dutifulbob)

---------

Co-authored-by: Onur <[email protected]>

* docs(telegram): recommend allowlist for single-user DM policy (#34841)

* docs(telegram): recommend allowlist for single-user bots

* docs(telegram): condense single-user allowlist note

---------

Co-authored-by: echoVic <[email protected]>

* fix(feishu): check response.ok before calling response.json() in streaming card (#35628)

Merged via squash.

Prepared head SHA: 62c3fec80d97cea9be344c0bef5358a0a5dc5560
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Mattermost: honor onmessage mention override and add gating diagnostics tests (#27160)

Merged via squash.

Prepared head SHA: 6cefb1d5bf3d6dfcec36c1cee3f9ea887f10c890
Co-authored-by: turian <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm

* fix(subagents): strip leaked [[reply_to]] tags from completion announces (#34503)

* fix(subagents): strip reply tags from completion delivery text

* test(subagents): cover reply-tag stripping in cron completion sends

* changelog: note iMessage reply-tag stripping in completion announces

* Update CHANGELOG.md

* Apply suggestion from @greptile-apps[bot]

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix(cron): restore direct fallback after announce failure in best-effort mode (openclaw#36177)

Verified:
- pnpm build
- pnpm check (fails on pre-existing origin/main lint debt in extensions/mattermost imports)
- pnpm test:macmini

Co-authored-by: Tak Hoffman <[email protected]>

* test(cron): add cross-channel announce fallback regression coverage (openclaw#36197)

Verified:
- pnpm install --frozen-lockfile
- pnpm build
- pnpm check (fails on pre-existing origin/main lint debt in extensions/mattermost imports)
- pnpm test:macmini

Co-authored-by: Tak Hoffman <[email protected]>

* feat(mattermost): add interactive buttons support (#19957)

Merged via squash.

Prepared head SHA: 8a25e608729d0b9fd07bb0ee4219d199d9796dbe
Co-authored-by: tonydehnke <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm

* fix(browser): remove deprecated --disable-blink-features=AutomationControlled flag

- Removes OpenClaw's default `--disable-blink-features=AutomationControlled` Chrome launch switch to avoid unsupported-flag warnings in newer Chrome (#35721).
- Preserves compatibility for older Chrome via `browser.extraArgs` override behavior (source analysis: #35770, #35728, #35727, #35885).
- Synthesis attribution: thanks @Sid-Qin, @kevinWangSheng, @ningding97, @Naylenv, @clawbie.

Source PR refs: #35734, #35770, #35728, #35727, #35885

Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: kevinWangSheng <[email protected]>
Co-authored-by: ningding97 <[email protected]>
Co-authored-by: Naylenv <[email protected]>
Co-authored-by: clawbie <[email protected]>
Co-authored-by: Takhoffman <[email protected]>

* fix(feishu): add HTTP timeout to prevent per-chat queue deadlocks (#36430)

When the Feishu API hangs or responds slowly, the sendChain never settles,
causing the per-chat queue to remain in a processing state forever and
blocking all subsequent messages in that thread. This adds a 30-second
default timeout to all Feishu HTTP requests by providing a timeout-aware
httpInstance to the Lark SDK client.

Closes #36412

Co-authored-by: Ayane <[email protected]>

* fix(feishu): use probed botName for mention checks (#36391)

* Feishu: honor bot mentions by ID despite aliases (Fixes #36317) (#36333)

* Mattermost: switch plugin-sdk imports to scoped subpaths (openclaw#36480)

Verified:
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: Takhoffman <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(feishu): accept groupPolicy "allowall" as alias for "open" (#36358)

* fix(feishu): accept groupPolicy "allowall" as alias for "open"

When users configure groupPolicy: "allowall" in Feishu channel config,
the Zod schema rejects the value and the runtime policy check falls
through to the allowlist path.  With an empty allowFrom array, all group
messages are silently dropped despite the intended "allow all" semantics.

Accept "allowall" at the schema level (transform to "open") and add a
runtime guard in isFeishuGroupAllowed so the value is handled even if it
bypasses schema validation.

Closes #36312

Made-with: Cursor

* Feishu: tighten allowall alias handling and coverage

---------

Co-authored-by: Tak Hoffman <[email protected]>

* synthesis: fix Feishu group mention slash parsing

## Summary\n\nFeishu group slash command parsing is fixed for mentions and command probes across authorization paths.\n\nThis includes:\n- Normalizing bot mention text in group context for reliable slash detection in message parsing.\n- Adding command-probe normalization for group slash invocations.\n\nCo-authored-by: Sid Qin <[email protected]>\nCo-authored-by: Tak Hoffman <[email protected]>

* Feishu: normalize group slash command probing

- Feishu/group slash command detection: normalize group mention wrappers before command-authorization probing so mention-prefixed commands are recognized in group routing.\n- Source PR: #36011\n- Contributor: @liuxiaopai-ai\n\nCo-authored-by: Tak Hoffman <[email protected]>\nCo-authored-by: liuxiaopai-ai <[email protected]>

* add prependSystemContext and appendSystemContext to before_prompt_build (fixes #35131) (#35177)

Merged via squash.

Prepared head SHA: d9a2869ad69db9449336a2e2846bd9de0e647ac6
Co-authored-by: maweibin <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(feishu): avoid media regressions from global HTTP timeout (#36500)

* fix(feishu): avoid media regressions from global http timeout

* fix(feishu): source HTTP timeout from config

* fix(feishu): apply media timeout override to image uploads

* fix(feishu): invalidate cached client when timeout changes

* fix(feishu): clamp timeout values and cover image download

* Gateway: add SecretRef support for gateway.auth.token with auth-mode guardrails (#35094)

* fix(embedded): classify model_context_window_exceeded as context overflow, trigger compaction (#35934)

Merged via squash.

Prepared head SHA: 20fa77289c80b2807a6779a3df70440242bc18ca
Co-authored-by: RealKai42 <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(agents): skip compaction API call when session has no real messages (#36451)

Merged via squash.

Prepared head SHA: 52dd6317895c7bd10855d2bd7dbbfc2f5279b68e
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(ui): catch marked.js parse errors to prevent Control UI crash (#36445)

- Prevent Control UI session render crashes when `marked.parse()` encounters pathological recursive markdown by safely falling back to escaped `<pre>` output.
- Tighten markdown fallback regression coverage and keep changelog attribution in sync for this crash-hardening path.

Co-authored-by: Bin Deng <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(session): archive old transcript on daily/scheduled reset to prevent orphaned files (#35493)

Merged via squash.

Prepared head SHA: 0d95549d752adecfc0b08d5cd55a8b8c75e264fe
Co-authored-by: byungsker <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(agents): set preserveSignatures to isAnthropic in resolveTranscriptPolicy (#32813)

Merged via squash.

Prepared head SHA: f522d21ca59a42abac554435a0aa646f6a34698d
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix: avoid false global rate-limit classification from generic cooldown text (#32972)

Merged via squash.

Prepared head SHA: 813c16f5afce415da130a917d9ce9f968912b477
Co-authored-by: stakeswky <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* refactor(agents): share failover HTTP status classification (#36615)

* fix(agents): classify transient failover statuses consistently

* fix(agents): preserve legacy failover status mapping

* fix(failover): narrow service-unavailable to require overload indicator (#32828) (#36646)

Merged via squash.

Prepared head SHA: 46fb4306127972d7635f371fd9029fbb9baff236
Co-authored-by: jnMetaCode <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* Compaction/Safeguard: add summary quality audit retries (#25556)

Merged via squash.

Prepared head SHA: be473efd1635616ebbae6e649d542ed50b4a827f
Co-authored-by: rodrigouroz <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* test(agents): add provider-backed failover regressions (#36735)

* test(agents): add provider-backed failover fixtures

* test(agents): cover more provider error docs

* test(agents): tighten provider doc fixtures

* Docs: add Slack typing reaction fallback

* Docs: update gateway config reference for Slack and TTS

* Docs: clarify OpenAI-compatible TTS endpoints

* Docs: document Control UI locale support

* Docs: cover heartbeat, cron, and plugin route updates

* fix(ui): bump dompurify to 3.3.2 (#36781)

* UI: bump dompurify to 3.3.2

* Deps: refresh dompurify lockfile

* UI: hoist lifecycle connect test mocks (#36788)

* fix(agents): classify insufficient_quota 400s as billing (#36783)

* feat: append UTC time alongside local time in shared Current time lines (#32423)

Merged via squash.

Prepared head SHA: 9e8ec13933b5317e7cff3f0bc048de515826c31a
Co-authored-by: jriff <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix(auth): grant senderIsOwner for internal channels with operator.admin scope (openclaw#35704)

Verified:
- pnpm install --frozen-lockfile
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: Naylenv <[email protected]>
Co-authored-by: Octane0411 <[email protected]>
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(config): prevent RangeError in merged schema cache key generation

Fix merged schema cache key generation for high-cardinality plugin/channel metadata by hashing incrementally instead of serializing one large aggregate string.

Includes changelog entry for the user-visible regression fix.

Co-authored-by: Tak Hoffman <[email protected]>
Co-authored-by: Bill <[email protected]>

* fix(slack): propagate mediaLocalRoots through Slack send path

Restore Slack local file upload parity with CVE-era local media allowlist enforcement by threading `mediaLocalRoots` through the Slack send call chain.

- pass `ctx.mediaLocalRoots` from Slack channel action adapter into `handleSlackAction`
- add and forward `mediaLocalRoots` in Slack action context/send path
- pass `mediaLocalRoots` into `sendMessageSlack` for upload allowlist enforcement
- add changelog entry with attribution for this behavior fix

Co-authored-by: 2233admin <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(slack): preserve dedupe while recovering dropped app_mention (#34937)

This PR fixes Slack mention loss without reintroducing duplicate dispatches.

- Preserve seen-message dedupe at ingress to prevent duplicate processing.
- Allow a one-time app_mention retry only when the paired message event was previously dropped before dispatch.
- Add targeted race tests for both recovery and duplicate-prevention paths.

Co-authored-by: littleben <[email protected]>
Co-authored-by: OpenClaw Agent <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* README: add algal to contributors list (#2046)

* fix: decouple Discord inbound worker timeout from listener timeout (#36602) (thanks @dutifulbob) (#36602)

Co-authored-by: Onur Solmaz <[email protected]>

* plugins: enforce prompt hook policy with runtime validation (#36567)

Merged via squash.

Prepared head SHA: 6b9d883b6ae33628235fb02ce39c0d0f46a065bb
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(memory): avoid destructive qmd collection rebinds

* Harden Telegram poll gating and schema consistency (#36547)

Merged via squash.

Prepared head SHA: f77824419e3d166f727474a9953a063a2b4547f2
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(browser): close tracked tabs on session cleanup (#36666)

* Diffs: restore system prompt guidance (#36904)

Merged via squash.

Prepared head SHA: 1b3be3c87957c068473d5c86b9efba4a1a8503f2
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(routing): avoid full binding rescans in resolveAgentRoute (#36915)

* fix(gateway): honor insecure ws override for remote hostnames

* fix(llm-task): load runEmbeddedPiAgent from dist/extensionAPI in installs

* fix(auth): harden openai-codex oauth login path

* feat(telegram/acp): Topic Binding, Pin Binding Message, Fix Spawn Param Parsing (#36683)

* fix(acp): normalize unicode flags and Telegram topic binding

* feat(telegram/acp): restore topic-bound ACP and session bindings

* fix(acpx): clarify permission-denied guidance

* feat(telegram/acp): pin spawn bind notice in topics

* docs(telegram): document ACP topic thread binding behavior

* refactor(reply): share Telegram conversation-id resolver

* fix(telegram/acp): preserve bound session routing semantics

* fix(telegram): respect binding persistence and expiry reporting

* refactor(telegram): simplify binding lifecycle persistence

* fix(telegram): bind acp spawns in direct messages

* fix: document telegram ACP topic binding changelog (#36683) (thanks @huntharo)

---------

Co-authored-by: Onur <[email protected]>

* fix(gateway): preserve streamed prefixes across tool boundaries

* fix(tui): prevent stale model indicator after /model

* Memory: handle SecretRef keys in doctor embeddings (#36835)

Merged via squash.

Prepared head SHA: c1a3d0caae60115d886e8bfc9983c9533c773f04
Co-authored-by: joshavant <[email protected]>
Co-authored-by: joshavant <[email protected]>
Reviewed-by: @joshavant

* fix(openai-codex): request required oauth api scopes (#24720)

* fix(memory-flush): ban timestamped variant files in default flush prompt (#34951)

Merged via squash.

Prepared head SHA: efadda4988b460e6da07be72994d4951d64239d0
Co-authored-by: zerone0x <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(tui): render final event error when assistant output is empty (#14687)

* feat(agents): flush reply pipeline before compaction wait (#35489)

Merged via squash.

Prepared head SHA: 7dbbcc510b74b0e8d35eb750d24575e34b5d769a
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(secrets): harden api key normalization for ByteString headers

* fix(slack): remove double mrkdwn conversion in native streaming path

Remove redundant text normalization from Slack native streaming markdown_text flow so Markdown formatting is preserved.

Synthesis context: overlaps reviewed from #34931, #34759, #34716, #34682, #34814.

Co-authored-by: littleben <[email protected]>
Co-authored-by: dunamismax <[email protected]>
Co-authored-by: Octane <[email protected]>
Co-authored-by: Mitsuyuki Osabe <[email protected]>
Co-authored-by: Kai <[email protected]>
Co-authored-by: OpenClaw Agent <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(kimi-coding): normalize anthropic tool payload format

* fix(slack): thread channel ID through inbound context for reactions (#34831)

Slack reaction/thread context routing fixes via canonical synthesis of #34831.

Co-authored-by: Tak <[email protected]>

* fix(heartbeat): pin HEARTBEAT.md reads to workspace path

* fix(subagents): recover announce cleanup after kill/complete race

* feat(hooks): emit compaction lifecycle hooks (#16788)

* fix(auth): harden openai-codex oauth refresh fallback

* fix(subagents): announce delivery with descendant gating, frozen result refresh, and cron retry (#35080)

Thanks @tyler6204

* fix(agents): avoid synthetic tool-result writes on idle-timeout cleanup

* fix(agent): harden undici stream timeouts for long openai-completions runs

* fix(slack): record app_mention retry key before dedupe check (#37033)

- Prime app_mention retry allowance before dedupe so near-simultaneous message/app_mention races do not drop valid mentions.
- Prevent duplicate dispatch when app_mention wins the race and message prepare later succeeds.
- Prune dispatched mention keys and add regression coverage for both dropped and successful in-flight message outcomes.

Co-authored-by: Tak Hoffman <[email protected]>

* fix(agents): honor explicit rate-limit cooldown probes in fallback runs

* fix(agents): allow configured ollama endpoints without dummy api keys

* fix(memory): recover qmd updates from duplicate document constraints

* Doctor: warn on implicit heartbeat directPolicy (#36789)

* Changelog: note heartbeat directPolicy doctor warning

* Tests: cover heartbeat directPolicy doctor warning

* Doctor: warn on implicit heartbeat directPolicy

* Tests: cover per-agent heartbeat directPolicy warning

* Update CHANGELOG.md

* Plugins: clarify registerHttpHandler migration errors (#36794)

* Changelog: note plugin HTTP route migration diagnostics

* Tests: cover registerHttpHandler migration diagnostics

* Plugins: clarify registerHttpHandler migration errors

* Tests: cover registerHttpHandler diagnostic edge cases

* Plugins: tighten registerHttpHandler migration hint

* fix(memory): repair qmd collection name conflicts during ensure

* fix(memory): handle qmd search results without docid

* Plugins: avoid false integrity drift prompts on unpinned updates (#37179)

* Plugins: skip drift prompts for unpinned updates

* Plugins: cover unpinned integrity update behavior

* Changelog: add #37179 release note

* Delete changelog/fragments directory

* Update CHANGELOG.md

* fix(whatsapp): remove implicit [openclaw] self-chat prefix

* fix: remove config.schema from agent gateway tool (#7382)

Merged via squash.

Prepared head SHA: f34a7780690a941936b31899e2d096b8a07f4afc
Co-authored-by: kakuteki <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* feat(openai): add gpt-5.4 support for API and Codex OAuth (#36590)

* feat(openai): add gpt-5.4 support and priority processing

* feat(openai-codex): add gpt-5.4 oauth support

* fix(openai): preserve provider overrides in gpt-5.4 fallback

* fix(openai-codex): keep xhigh for gpt-5.4 default

* fix(models): preserve configured overrides in list output

* fix(models): close gpt-5.4 integration gaps

* fix(openai): scope service tier to public api

* fix(openai): complete prep followups for gpt-5.4 support (#36590) (thanks @dorukardahan)

---------

Co-authored-by: Tyler Yust <[email protected]>

* fix(tui): preserve credential-like tokens in render sanitization

* CLI: make read-only SecretRef status flows degrade safely (#37023)

* CLI: add read-only SecretRef inspection

* CLI: fix read-only SecretRef status regressions

* CLI: preserve read-only SecretRef status fallbacks

* Docs: document read-only channel inspection hook

* CLI: preserve audit coverage for read-only SecretRefs

* CLI: fix read-only status account selection

* CLI: fix targeted gateway fallback analysis

* CLI: fix Slack HTTP read-only inspection

* CLI: align audit credential status checks

* CLI: restore Telegram read-only fallback semantics

* chore(changelog): update for #37023

Signed-off-by: joshavant <[email protected]>

* fix(agents): disable usage streaming chunks on non-native openai-completions

* feat(nano-banana-pro): add --aspect-ratio flag to generate_image.py (#28159)

* feat(nano-banana-pro): add --aspect-ratio flag to generate_image.py

* Nano Banana: allow all supported aspect ratios

* Docs: expand nano banana aspect ratio options

---------

Co-authored-by: Vincent Koc <[email protected]>

* fix(gateway): support image_url in OpenAI chat completions (#34068)

* fix(gateway): parse image_url in openai chat completions

* test(gateway): cover openai chat completions image_url flows

* docs(changelog): note openai image_url chat completions fix (#17685)

* fix(gateway): harden openai image_url parsing and limits

* test(gateway): add openai image_url regression coverage

* docs(changelog): expand #17685 openai chat completions note

* Gateway: make OpenAI image_url URL fetch opt-in and configurable

* Diagnostics: redact image base64 payload data in trace logs

* Changelog: note OpenAI image_url hardening follow-ups

* Gateway: enforce OpenAI image_url total budget incrementally

* Gateway: scope OpenAI image_url extraction to the active turn

* Update CHANGELOG.md

* fix(agents): avoid xAI web_search tool-name collisions

* fix: clear Telegram DM draft after materialize (#36746) (thanks @joelnishanth)

* Fix Control UI duplicate iMessage replies for internal webchat turns (#36151)

* Auto-reply: avoid routing external replies from internal webchat turns

* Auto-reply tests: cover internal webchat non-routing with external origin metadata

* Changelog: add Control UI iMessage duplicate-reply fix note

* Auto-reply context: track explicit deliver routes

* Gateway chat: mark explicit external deliver routes in context

* Auto-reply: preserve explicit deliver routes for internal webchat turns

* Auto-reply tests: cover explicit deliver routes from internal webchat turns

* Gateway chat tests: assert explicit deliver route context tagging

* fix: enforce 600 perms for cron store and run logs (#36078)

* fix: enforce secure permissions for cron store and run logs

* fix(cron): enforce dir perms and gate posix tests on windows

* Cron store tests: cover existing directory permission hardening

* Cron run-log tests: cover existing directory permission hardening

* Changelog: note cron file permission hardening

---------

Co-authored-by: linhey <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>

* fix(tui): accept canonical session-key aliases in chat event routing

* Gateway: normalize OpenAI stream chunk text

* Gateway: coerce chat deliverable route boolean

* fix(web_search): align brave language codes with API

* Respect source channel for agent event surfacing (#36030)

* fix(session): prefer webchat routes for direct ui turns (#37135)

* Gateway: discriminate input sources

* Cron: migrate legacy provider delivery hints

* Cron: stabilize runs-one-shot migration tests

* fix(memory): retry mcporter after Windows EINVAL spawn

* fix(onboarding): guard daemon status probe on headless linux

* Gateway: add path-scoped config schema lookup (#37266)

Merged via squash.

Prepared head SHA: 0c4d187f6fb66f2799d4047585d6368e433c883a
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* docs(changelog): add pr entry

* fix(ci): restore protocol and schema checks (#37470)

* Fix failover for zhipuai 1310 Weekly/Monthly Limit Exhausted (#33813)

Merged via squash.

Prepared head SHA: 3dc441e58de48913720cf7b6137fa761758d8344
Co-authored-by: zhouhe-xydt <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix(openai-codex-oauth): stop mutating authorize url scopes

* Update CHANGELOG.md

* fix(auth): remove bogus codex oauth responses probe

* docs(changelog): fold codex oauth fix notes

* docs(changelog): add codex oauth pr reference (#37558)

* fix(security:PLA-697): block local secret scratch files from commits

* feat: add dev EKS deployment for openclaw SRE container

* fix: stabilize slack socket mode in dev eks runtime

* fix(eks): reuse monitoring incident auth for openclaw-sre

* feat(deploy): add grafana env guards and prod deploy wrapper

* fix(security): redact tool outputs and enforce secret-safe runtime defaults

* feat(sre): harden heartbeat routing and enrich triage signals

* docs: add SRE hybrid intelligence design

Three-layer architecture to improve bot reasoning quality:
- Layer 1: Service knowledge (auto-discovery + overlays + incident memory)
- Layer 2: Multi-stage reasoning chain (triage → hypothesize → causal chain → action plan → cross-review)
- Layer 3: Incident learning loop (structured cards, overlay suggestions, feedback signals)

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* feat(sandbox): add boundary cli to common runtime image

* docs(sre): finalize hybrid intelligence design v19 after 18 Codex review rounds

Iteratively hardened the design through 18 adversarial Codex review rounds,
resolving 60+ findings (15+ CRITICAL, 45+ HIGH). Key fixes include:
- Decoupled incident_id (pre-Step11 immutable) from card_id (LLM-derived)
- Unified evidence/memory sanitization via shared _strip_instruction_tokens
- Fixed rerun interval default (3600s > heartbeat 1800s) to prevent every-cycle re-runs
- Added Phase 2 cross-review gap note and dual-column depth table
- Overlay suggestion idempotency via deterministic suggestion_key + upsert
- Decoupled chain timeout from legacy budget check
- Added predicate alignment docs for L3 pre-check vs L3 gate
- Adopted dynamic evidence_completeness denominator matching existing code
- Added scope note clarifying design vs current implementation

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* feat(sre): complete hybrid intelligence rollout and bot hardening

* fix(sre): harden slack reasoning, dual chain, and deploy auth/runtime

* ci: add ecr release pipeline and infra-helm image update trigger

* ci: switch workflows to github-hosted runners

* ci: allow manual ecr env target and use updater v4

* ci: remove windows jobs from workflow

* chore(pla-678): update fallback auth fixture and plan docs

* fix(pla-678): preserve control-ui host-header fallback in dev config

* refactor(pla-678): remove local sre chart and require infra-helm

* refactor(pla-678): remove direct eks deploy scripts

* ci(pla-678): remove labeler workflow

* ci(pla-678): refresh checks after disabling labeler

* build: install boundary CLI in SRE runtime image

* fix(slack:PLA-678): keep one thread lane across users

* fix(sre-skill): enforce live db-query runbook in dev seed

* fix(slack): ignore bot thread history when seeding new sessions

* fix(slack): force retry on repeated thread questions

* fix(sre-skill): require retry on repeated db requests

* docs(sre-skill): make retry policy generic across repeated asks

* fix(sre:PLA-678): enforce live linear ticket updates

* fix(sre:PLA-678): use [PLATFORM] Backlog linear project

* fix(sre:PLA-678): label linked linear tickets as openclaw-sre

* fix(sre:PLA-678): auto-label linked linear tickets for auto-pr

* test(sre:PLA-678): make tracking label test executable

* fix(slack:PLA-678): remove status-final completion banner (#16)

* fix(slack:PLA-678): enable direct file attachments from agent replies (#17)

* fix(slack:PLA-678): remove status-final completion banner

* fix(slack): enable direct file attachments from agent replies

* refactor(sre:PLA-678): remove local deploy config mirror (#18)

* fix: compact oversized auto-generated pr bodies

* fix(sre): add built-in linear incident memory provider

* feat(sre): add erpc helper with flo secret query

* fix(sre): enforce canonical rpc.morpho.dev erpc endpoint

* refactor(sre): remove local deploy config mirror

* fix(slack:PLA-678): force DM replies into per-message threads (#19)

* fix: compact oversized auto-generated pr bodies

* fix(sre): add built-in linear incident memory provider

* feat(sre): add erpc helper with flo secret query

* fix(sre): enforce canonical rpc.morpho.dev erpc endpoint

* refactor(sre): remove local deploy config mirror

* fix(slack): force threaded replies for direct messages

* feat(cron:PLA-678): use conversation history in self-improve runs (#20)

* fix(slack:PLA-678): improve progress update readability (#21)

* fix(ci:PLA-678): restore main release pipeline health (#22)

* fix(ci:PLA-678): restore main release pipeline health

* fix(ci:PLA-678): harden auto-response token fallback

* fix(ci:PLA-678): pin setup-bun to published release

* test(ci:PLA-678): align slack thread session expectations

* fix(sre:PLA-678): harden Slack reply delivery and image release flow (#23)

* fix(slack:PLA-678): harden thread-scoped reply delivery

* fix(slack:PLA-678): satisfy lint after rebase

* ci(release:PLA-678): move image release to cached ecr flow

* ci(release:PLA-678): use official docker build actions

* fix(slack:PLA-722): preserve progress updates during final-answer gating (#24)

* fix(sre:PLA-724): restore ECR runtime image toolchain (#25)

* fix(failover): classify HTTP 402 as rate_limit when payload indicates usage limit (#30484) (#36802)

* fix(failover): classify HTTP 402 as rate_limit when payload indicates usage limit (#30484)

Some providers (notably Anthropic Claude Max plan) surface temporary
usage/rate-limit failures as HTTP 402 instead of 429. Before this change,
all 402s were unconditionally mapped to 'billing', which produced a
misleading 'run out of credits' warning for Max plan users who simply
hit their usage window.

This follows the same pattern introduced for HTTP 400 in #36783: check
the error message for an explicit rate-limit signal before falling back
to the default status-code classification.

- classifyFailoverReasonFromHttpStatus now returns 'rate_limit' for 402
  when isRateLimitErrorMessage matches the payload text
- Added regression tests covering both the rate-limit and billing paths
  on 402

* fix: narrow 402 rate-limit matcher to prevent billing misclassification

The original implementation used isRateLimitErrorMessage(), which matches
phrases like 'quota exceeded' that legitimately appear in billing errors.

This commit replaces it with a narrow, 402-specific matcher that requires
BOTH retry language (try again/retry/temporary/cooldown) AND limit
terminology (usage limit/rate limit/organization usage).

Prevents misclassification of errors like:
'HTTP 402: exceeded quota, please add credits' -> billing (not rate_limit)

Added regression test for the ambiguous case.

---------

Co-authored-by: Val Alexander <[email protected]>

* fix(mattermost): allow reachable interaction callback URLs (#37543)

Merged via squash.

Prepared head SHA: 4d593731be5a5dcbf3106d596b38acfeb8cf0aa8
Co-authored-by: mukhtharcm <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm

* fix(cron:PLA-740): audit previous-day self-improve sessions

---------

Signed-off-by: joshavant <[email protected]>
Co-authored-by: Gustavo Madeira Santana <[email protected]>
Co-authored-by: Mariano <[email protected]>
Co-authored-by: leepokai <[email protected]>
Co-authored-by: Bob <[email protected]>
Co-authored-by: Onur <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
Co-authored-by: huangcj <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: Sid <[email protected]>
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Co-authored-by: a <[email protected]>
Co-authored-by: echoVic <[email protected]>
Co-authored-by: Shakker <[email protected]>
Co-authored-by: liuxiaopai-ai <[email protected]>
Co-authored-by: Rodrigo Uroz <[email protected]>
Co-authored-by: rodrigouroz <[email protected]>
Co-authored-by: jalehman <[email protected]>
Co-authored-by: Kai <[email protected]>
Co-authored-by: RealKai42 <[email protected]>
Co-authored-by: 青雲 <[email protected]>
Co-authored-by: echoVic <[email protected]>
Co-authored-by: Darshil <[email protected]>
Co-authored-by: Ho Lim <[email protected]>
Co-authored-by: dvrshil <[email protected]>
Co-authored-by: Isis Anisoptera <[email protected]>
Co-authored-by: Madoka <[email protected]>
Co-authored-by: Xu Zimo <[email protected]>
Co-authored-by: Munem Hashmi <[email protected]>
Co-authored-by: bmendonca3 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>
Co-authored-by: Nhj <[email protected]>
Co-authored-by: 倪汉杰0668001185 <[email protected]>
Co-authored-by: zhengquanliu <[email protected]>
Co-authored-by: nick <[email protected]>
Co-authored-by: linhey <[email protected]>
Co-authored-by: scoootscooob <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: rexl2018 <[email protected]>
Co-authored-by: sline <[email protected]>
Co-authored-by: 0xsline <[email protected]>
Co-authored-by: Harold Hunt <[email protected]>
Co-authored-by: Shivam <[email protected]>
Co-authored-by: 不做了睡大觉 <[email protected]>
Co-authored-by: alexyyyander <[email protected]>
Co-authored-by: alexyyyander <[email protected]>
Co-authored-by: Octane0411 <[email protected]>
Co-authored-by: Linux2010 <[email protected]>
Co-authored-by: echoVic <[email protected]>
Co-authored-by: Joseph Turian <[email protected]>
Co-authored-by: turian <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Tony Dehnke <[email protected]>
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: kevinWangSheng <[email protected]>
Co-authored-by: ningding97 <[email protected]>
Co-authored-by: Naylenv <[email protected]>
Co-authored-by: clawbie <[email protected]>
Co-authored-by: Takhoffman <[email protected]>
Co-authored-by: Ayane <[email protected]>
Co-authored-by: Ayane <[email protected]>
Co-authored-by: StingNing <[email protected]>
Co-authored-by: maweibin <[email protected]>
Co-authored-by: maweibin <[email protected]>
Co-authored-by: Josh Avant <[email protected]>
Co-authored-by: Bin Deng <[email protected]>
Co-authored-by: Byungsker <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Co-authored-by: Altay <[email protected]>
Co-authored-by: jiangnan <[email protected]>
Co-authored-by: jnMetaCode <[email protected]>
Co-authored-by: Jacob Riff <[email protected]>
Co-authored-by: jriff <[email protected]>
Co-authored-by: Naylenv <[email protected]>
Co-authored-by: Bill <[email protected]>
Co-authored-by: 2233admin <[email protected]>
Co-authored-by: 2233admin <[email protected]>
Co-authored-by: littleben <[email protected]>
Co-authored-by: littleben <[email protected]>
Co-authored-by: OpenClaw Agent <[email protected]>
Co-authored-by: Vignesh Natarajan <[email protected]>
Co-authored-by: zerone0x <[email protected]>
Co-authored-by: zerone0x <[email protected]>
Co-authored-by: dunamismax <[email protected]>
Co-authored-by: Octane <[email protected]>
Co-authored-by: Mitsuyuki Osabe <[email protected]>
Co-authored-by: Tak <[email protected]>
Co-authored-by: Tyler Yust <[email protected]>
Co-authored-by: Hinata Kaga (samon) <[email protected]>
Co-authored-by: dorukardahan <[email protected]>
Co-authored-by: Tyler Yust <[email protected]>
Co-authored-by: Brenner Spear <[email protected]>
Co-authored-by: aerelune <[email protected]>
Co-authored-by: Frank Yang <[email protected]>
Co-authored-by: zhouhe-xydt <[email protected]>
Co-authored-by: zhouhe-xydt <[email protected]>
Co-authored-by: Vignesh <[email protected]>
Co-authored-by: OpenClaw SRE Bot <[email protected]>
Co-authored-by: Xinhua Gu <[email protected]>
Co-authored-by: Val Alexander <[email protected]>
0x666c6f added a commit to 0x666c6f/openclaw that referenced this pull request Mar 26, 2026
…openclaw#31)

* Plugins/memory-lancedb: migrate to scoped plugin-sdk imports

* Plugins/minimax-portal-auth: migrate to scoped plugin-sdk imports

* Plugins/msteams: migrate to scoped plugin-sdk imports

* Plugins/nextcloud-talk: migrate to scoped plugin-sdk imports

* Plugins/nostr: migrate to scoped plugin-sdk imports

* Plugins/open-prose: migrate to scoped plugin-sdk imports

* Plugins/phone-control: migrate to scoped plugin-sdk imports

* Plugins/qwen-portal-auth: migrate to scoped plugin-sdk imports

* Plugins/synology-chat: migrate to scoped plugin-sdk imports

* Plugins/talk-voice: migrate to scoped plugin-sdk imports

* Plugins/test-utils: migrate to scoped plugin-sdk imports

* Plugins/thread-ownership: migrate to scoped plugin-sdk imports

* Plugins/tlon: migrate to scoped plugin-sdk imports

* Plugins/twitch: migrate to scoped plugin-sdk imports

* Plugins/voice-call: migrate to scoped plugin-sdk imports

* Plugins/whatsapp: migrate to scoped plugin-sdk imports

* Plugins/zalo: migrate to scoped plugin-sdk imports

* Plugins/zalouser: migrate to scoped plugin-sdk imports

* Chore: remove accidental .DS_Store artifact

* chore(docs): add plugins refactor changelog entry

* feat(ios): add Live Activity connection status + stale cleanup (#33591)

* feat(ios): add live activity connection status and cleanup

Add lock-screen/Dynamic Island connection health states and prune duplicate/stale activities before reuse. This intentionally excludes AI/title generation and heavier UX rewrites from #27488.

Co-authored-by: leepokai <[email protected]>

* fix(ios): treat ended live activities as inactive

* chore(changelog): add PR reference and author thanks

---------

Co-authored-by: leepokai <[email protected]>

* fix: kill stuck ACP child processes on startup and harden sessions in discord threads (#33699)

* Gateway: resolve agent.wait for chat.send runs

* Discord: harden ACP thread binding + listener timeout

* ACPX: handle already-exited child wait

* Gateway/Discord: address PR review findings

* Discord: keep ACP error-state thread bindings on startup

* gateway: make agent.wait dedupe bridge event-driven

* discord: harden ACP probe classification and cap startup fan-out

* discord: add cooperative timeout cancellation

* discord: fix startup probe concurrency helper typing

* plugin-sdk: avoid Windows root-alias shard timeout

* plugin-sdk: keep root alias reflection path non-blocking

* discord+gateway: resolve remaining PR review findings

* gateway+discord: fix codex review regressions

* Discord/Gateway: address Codex review findings

* Gateway: keep agent.wait lifecycle active with shared run IDs

* Discord: clean up status reactions on aborted runs

* fix: add changelog note for ACP/Discord startup hardening (#33699) (thanks @dutifulbob)

---------

Co-authored-by: Onur <[email protected]>

* fix: relay ACP sessions_spawn parent streaming (#34310) (thanks @vincentkoc) (#34310)

Co-authored-by: Onur Solmaz <[email protected]>

* fix(telegram): materialize dm draft final to avoid duplicates

* docs(changelog): credit @Brotherinlaw-13 for #34318

* fix: prevent nodes media base64 context bloat (#34332)

* fix: preserve raw media invoke for HTTP tool clients (#34365)

* fix(slack): route system events to bound agent sessions (#34045)

* fix(slack): route system events via binding-aware session keys

* fix(slack): pass sender to system event session resolver

* fix(slack): include sender context for interaction session routing

* fix(slack): include modal submitter in session routing

* test(slack): cover binding-aware system event routing

* test(slack): update interaction session key assertions

* test(slack): assert reaction session routing carries sender

* docs(changelog): note slack system event routing fix

* Update CHANGELOG.md

* Delete changelog/fragments directory

* fix(memory): serialize local embedding initialization to avoid duplicate model loads (#15639)

Merged via squash.

Prepared head SHA: a085fc21a8ba7163fffdb5de640dd4dc1ff5a88e
Co-authored-by: SubtleSpark <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(model): propagate custom provider headers to model objects (#27490)

Merged via squash.

Prepared head SHA: e4183b398fc7eb4c18b2b691cb0dd882ec993608
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(daemon): handle systemctl is-enabled exit 4 (not-found) on Ubuntu (#33634)

Merged via squash.

Prepared head SHA: 67dffc3ee239cd7b813cb200c3dd5475d9e203a6
Co-authored-by: Yuandiaodiaodiao <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(node-host): sync rawCommand with hardened argv after executable path pinning (#33137)

Merged via squash.

Prepared head SHA: a7987905f7ad6cf5fee286ffa81ceaad8297174f
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* Agents: add generic poll-vote action support

* fix(ollama): pass provider headers to Ollama stream function (#24285)

createOllamaStreamFn() only accepted baseUrl, ignoring custom headers
configured in models.providers.<provider>.headers. This caused 403
errors when Ollama endpoints are behind reverse proxies that require
auth headers (e.g. X-OLLAMA-KEY via HAProxy).

Add optional defaultHeaders parameter to createOllamaStreamFn() and
merge them into every fetch request. Provider headers from config are
now passed through at the call site in the embedded runner.

Fixes #24285

* test(ollama): add default header precedence coverage

* chore(changelog): add PR entry openclaw#24337 thanks @echoVic

* Outbound: allow text-only plugin adapters

* Outbound: avoid empty multi-media fallback sends

* chore(changelog): align outbound adapter entry openclaw#32788 thanks @liuxiaopai-ai

* fix(outbound): fail media-only text-only adapter fallback

* chore(changelog): clarify outbound media-only fallback openclaw#32788 thanks @liuxiaopai-ai

* fix(review): enforce behavioral sweep validation

* Fix gateway restart false timeouts on Debian/systemd (#34874)

* daemon(systemd): target sudo caller user scope

* test(systemd): cover sudo user scope commands

* infra(ports): fall back to ss when lsof missing

* test(ports): verify ss fallback listener detection

* cli(gateway): use probe fallback for restart health

* test(gateway): cover restart-health probe fallback

* Compaction/Safeguard: require structured summary headings (#25555)

Merged via squash.

Prepared head SHA: 0b1df34806a7b788261290be55760fd89220de53
Co-authored-by: rodrigouroz <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Fix Linux daemon install checks when systemd user bus env is missing (#34884)

* daemon(systemd): fall back to machine user scope when user bus is missing

* test(systemd): cover machine scope fallback for user-bus errors

* test(systemd): reset execFile mock state across cases

* test(systemd): make machine-user fallback assertion portable

* fix(daemon): keep root sudo path on direct user scope

* test(systemd): cover sudo root user-scope behavior

* ci: use resolvable bun version in setup-node-env

* agents: preserve totalTokens on request failure instead of using contextWindow (#34275)

Merged via squash.

Prepared head SHA: f9d111d0a79a07815d476356e98a28df3a0000ba
Co-authored-by: RealKai42 <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix: align AGENTS.md template section names with post-compaction extraction (#25029) (#25098)

Merged via squash.

Prepared head SHA: 8cd6cc8049aab5a94d8a9d5fb08f2e792c4ac5fd
Co-authored-by: echoVic <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Changelog: add daemon systemd user-bus fallback entry (#34884)

* Changelog: add gateway restart health entry (#34874)

* fix: finalize spanish locale support

* fix: add spanish locale support (#35038) (thanks @DaoPromociones)

* fix(deps): patch hono transitive audit vulnerabilities

* fix(security): avoid prototype-chain account path checks (#34982)

Merged via squash.

Prepared head SHA: f89cc6a649959997fe1dec1e1c1bff9a61b2de98
Co-authored-by: HOYALIM <[email protected]>
Co-authored-by: dvrshil <[email protected]>
Reviewed-by: @dvrshil

* fix(deps): bump tar to 7.5.10

* docs(changelog): document dependency security fixes

* fix: restore auto-reply system events timeline (#34794) (thanks @anisoptera) (#34794)

Co-authored-by: Ayaan Zaidi <[email protected]>

* fix(feishu): comprehensive reply mechanism — outbound replyToId forwarding + topic-aware reply targeting (#33789)

* fix(feishu): comprehensive reply mechanism fix — outbound replyToId forwarding + topic-aware reply targeting

- Forward replyToId from ChannelOutboundContext through sendText/sendMedia
  to sendMessageFeishu/sendMarkdownCardFeishu/sendMediaFeishu, enabling
  reply-to-message via the message tool.

- Fix group reply targeting: use ctx.messageId (triggering message) in
  normal groups to prevent silent topic thread creation (#32980). Preserve
  ctx.rootId targeting for topic-mode groups (group_topic/group_topic_sender)
  and groups with explicit replyInThread config.

- Add regression tests for both fixes.

Fixes #32980
Fixes #32958
Related #19784

* fix: normalize Feishu delivery.to before comparing with messaging tool targets

- Add normalizeDeliveryTarget helper to strip user:/chat: prefixes for Feishu
- Apply normalization in matchesMessagingToolDeliveryTarget before comparison
- This ensures cron duplicate suppression works when session uses prefixed targets
  (user:ou_xxx) but messaging tool extract uses normalized bare IDs (ou_xxx)

Fixes review comment on PR #32755

(cherry picked from commit fc20106f16ccc88a5f02e58922bb7b7999fe9dcd)

* fix(feishu): catch thrown SDK errors for withdrawn reply targets

The Feishu Lark SDK can throw exceptions (SDK errors with .code or
AxiosErrors with .response.data.code) for withdrawn/deleted reply
targets, in addition to returning error codes in the response object.

Wrap reply calls in sendMessageFeishu and sendCardFeishu with
try-catch to handle thrown withdrawn/not-found errors (230011,
231003) and fall back to client.im.message.create, matching the
existing response-level fallback behavior.

Also extract sendFallbackDirect helper to deduplicate the
direct-send fallback block across both functions.

Closes #33496

(cherry picked from commit ad0901aec103a2c52f186686cfaf5f8ba54b4a48)

* feishu: forward outbound reply target context

(cherry picked from commit c129a691fcf552a1cebe1e8a22ea8611ffc3b377)

* feishu extension: tighten reply target fallback semantics

(cherry picked from commit f85ec610f267020b66713c09e648ec004b2e26f1)

* fix(feishu): align synthesized fallback typing and changelog attribution

* test(feishu): cover group_topic_sender reply targeting

---------

Co-authored-by: Xu Zimo <[email protected]>
Co-authored-by: Munem Hashmi <[email protected]>
Co-authored-by: bmendonca3 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(feishu): use msg_type media for mp4 video (fixes #33674) (#33720)

* fix(feishu): use msg_type media for mp4 video (fixes #33674)

* Feishu: harden streaming merge semantics and final reply dedupe

Use explicit streaming update semantics in the Feishu reply dispatcher:
treat onPartialReply payloads as snapshot updates and block fallback payloads
as delta chunks, then merge final text with the shared overlap-aware
mergeStreamingText helper before closing the stream.

Prevent duplicate final text delivery within the same dispatch cycle, and add
regression tests covering overlap snapshot merge, duplicate final suppression,
and block-as-delta behavior to guard against repeated/truncated output.

* fix(feishu): prefer message.reply for streaming cards in topic threads

* fix: reduce Feishu streaming card print_step to avoid duplicate rendering

Fixes openclaw/openclaw#33751

* Feishu: preserve media sends on duplicate finals and add media synthesis changelog

* Feishu: only dedupe exact duplicate final replies

* Feishu: use scoped plugin-sdk import in streaming-card tests

---------

Co-authored-by: 倪汉杰0668001185 <[email protected]>
Co-authored-by: zhengquanliu <[email protected]>
Co-authored-by: nick <[email protected]>
Co-authored-by: linhey <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(agents): bypass pendingDescendantRuns guard for cron announce delivery (#35185)

* fix(agents): bypass pendingDescendantRuns guard for cron announce delivery

Standalone cron job completions were blocked from direct channel delivery
when the cron run had spawned subagents that were still registered as
pending. The pendingDescendantRuns guard exists for live orchestration
coordination and should not apply to fire-and-forget cron announce sends.

Thread the announceType through the delivery chain and skip both the
child-descendant and requester-descendant pending-run guards when the
announce originates from a cron job.

Closes #34966

* fix: ensure outbound session entry for cron announce with named agents (#32432)

Named agents may not have a session entry for their delivery target,
causing the announce flow to silently fail (delivered=false, no error).

Two fixes:
1. Call ensureOutboundSessionEntry when resolving the cron announce
   session key so downstream delivery can find channel metadata.
2. Fall back to direct outbound delivery when announce delivery fails
   to ensure cron output reaches the target channel.

Closes #32432

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: guard announce direct-delivery fallback against suppression leaks (#32432)

The `!delivered` fallback condition was too broad — it caught intentional
suppressions (active subagents, interim messages, SILENT_REPLY_TOKEN) in
addition to actual announce delivery failures.  Add an
`announceDeliveryWasAttempted` flag so the direct-delivery fallback only
fires when `runSubagentAnnounceFlow` was actually called and failed.

Also remove the redundant `if (route)` guard in
`resolveCronAnnounceSessionKey` since `resolved` being truthy guarantees
`route` is non-null.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix(cron): harden announce synthesis follow-ups

---------

Co-authored-by: scoootscooob <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* Feishu: harden streaming merge semantics and final reply dedupe (#33245)

* Feishu: close duplicate final gap and cover routing precedence

* Feishu: resolve reviewer duplicate-final and routing feedback

* Feishu: tighten streaming send-mode option typing

* Feishu: fix reverse-overlap streaming merge ordering

* Feishu: align streaming final dedupe test expectation

* Feishu: allow distinct streaming finals while deduping repeats

---------

Co-authored-by: Tak Hoffman <[email protected]>

* fix: cron backup should preserve pre-edit snapshot (#35195) (#35234)

* fix(cron): avoid overwriting .bak during normalization

Fixes openclaw/openclaw#35195

* test(cron): preserve pre-edit bak snapshot in normalization path

---------

Co-authored-by: 0xsline <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(cron): stabilize restart catch-up replay semantics (#35351)

* Cron: stabilize restart catch-up replay semantics

* Cron: respect backoff in startup missed-run replay

* cron: narrow startup replay backoff guard (#35391)

* cron: unify stale-run recovery and preserve manual-run every anchors (#35363)

* cron: unify stale-run recovery and preserve manual every anchors

* cron: address unresolved review threads on recovery paths

* cron: remove duplicate timestamp helper after rebase

* refactor(telegram): remove unused webhook callback helper (#27816)

* fix(pr): make review claim step required

* fix(skills): deduplicate slash commands by skillName across all interfaces

Move skill-command deduplication by skillName from the Discord-only
`dedupeSkillCommandsForDiscord` into `listSkillCommandsForAgents` so
every interface (TUI, Slack, text) consistently sees a clean command
list without platform-specific workarounds.

When multiple agents share a skill with the same name the old code
emitted `github` + `github_2` and relied on Discord to collapse them.
Now `listSkillCommandsForAgents` returns only the first registration
per skillName, and the Discord-specific wrapper is removed.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* style: fix formatting in skill-commands.test.ts and provider.ts

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* style(skills): align formatting cleanup for dedupe changes

* chore(changelog): add dedupe note openclaw#27521 thanks @shivama205

* fix(agents): detect Venice provider proxying xAI/Grok models for schema cleaning (#35355)

Merged via squash.

Prepared head SHA: 8bfdec257bb6a6025cb69a0a213a433da32b15db
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(agents): decode HTML entities in xAI/Grok tool call arguments (#35276)

Merged via squash.

Prepared head SHA: c4445d2938898ded9c046614f9315dbda65ec573
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(agents): guard promoteThinkingTagsToBlocks against malformed content entries (#35143)

Merged via squash.

Prepared head SHA: 3971122f5fd27c66c8c9c5ce783f00e113b1f47b
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(web-ui): render Accounts schema node properly (#35380)

Co-authored-by: stakeswky <[email protected]>
Co-authored-by: liuxiaopai-ai <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(agents): guard context pruning against malformed thinking blocks (#35146)

Merged via squash.

Prepared head SHA: a196a565b1b8e806ffbf85172bcf1128796b45a2
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* fix(gateway): prevent internal route leakage in chat.send

Synthesis of routing fixes from #35321, #34635, and #35356 for internal-client reply safety.

- Require explicit `deliver: true` before inheriting any external delivery route.
- Keep webchat/TUI/UI-origin traffic on internal routing by default.
- Allow configured-main session inheritance only for non-Webchat/UI clients, and honor `session.mainKey`.
- Add regression tests for UI no-inherit, configured-main CLI inherit, and deliver-flag behavior.

Co-authored-by: alexyyyander <[email protected]>
Co-authored-by: Octane0411 <[email protected]>
Co-authored-by: Linux2010 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(gateway): pass actual version to Control UI client instead of dev (#35230)

* fix(gateway): pass actual version to Control UI client instead of "dev"

The GatewayClient, CLI WS client, and browser Control UI all sent
"dev" as their clientVersion during handshake, making it impossible
to distinguish builds in gateway logs and health snapshots.

- GatewayClient and CLI WS client now use the resolved VERSION constant
- Control UI reads serverVersion from the bootstrap endpoint and
  forwards it when connecting
- Bootstrap contract extended with serverVersion field

Closes #35209

* Gateway: fix control-ui version version-reporting consistency

* Control UI: guard deferred bootstrap connect after disconnect

* fix(ui): accept same-origin http and relative gateway URLs for client version

---------

Co-authored-by: Tak Hoffman <[email protected]>

* chore(pr): enforce changelog placement and reduce merge sync churn

* TTS: add baseUrl support to OpenAI TTS config (#34321)

Merged via squash.

Prepared head SHA: e9a10cf81d2021cf81091dfa81e13ffdbb6a540a
Co-authored-by: RealKai42 <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Reviewed-by: @shakkernerd

* ACP: add persistent Discord channel and Telegram topic bindings (#34873)

* docs: add ACP persistent binding experiment plan

* docs: align ACP persistent binding spec to channel-local config

* docs: scope Telegram ACP bindings to forum topics only

* docs: lock bound /new and /reset behavior to in-place ACP reset

* ACP: add persistent discord/telegram conversation bindings

* ACP: fix persistent binding reuse and discord thread parent context

* docs: document channel-specific persistent ACP bindings

* ACP: split persistent bindings and share conversation id helpers

* ACP: defer configured binding init until preflight passes

* ACP: fix discord thread parent fallback and explicit disable inheritance

* ACP: keep bound /new and /reset in-place

* ACP: honor configured bindings in native command flows

* ACP: avoid configured fallback after runtime bind failure

* docs: refine ACP bindings experiment config examples

* acp: cut over to typed top-level persistent bindings

* ACP bindings: harden reset recovery and native command auth

* Docs: add ACP bound command auth proposal

* Tests: normalize i18n registry zh-CN assertion encoding

* ACP bindings: address review findings for reset and fallback routing

* ACP reset: gate hooks on success and preserve /new arguments

* ACP bindings: fix auth and binding-priority review findings

* Telegram ACP: gate ensure on auth and accepted messages

* ACP bindings: fix session-key precedence and unavailable handling

* ACP reset/native commands: honor fallback targets and abort on bootstrap failure

* Config schema: validate ACP binding channel and Telegram topic IDs

* Discord ACP: apply configured DM bindings to native commands

* ACP reset tails: dispatch through ACP after command handling

* ACP tails/native reset auth: fix target dispatch and restore full auth

* ACP reset detection: fallback to active ACP keys for DM contexts

* Tests: type runTurn mock input in ACP dispatch test

* ACP: dedup binding route bootstrap and reset target resolution

* reply: align ACP reset hooks with bound session key

* docs: replace personal discord ids with placeholders

* fix: add changelog entry for ACP persistent bindings (#34873) (thanks @dutifulbob)

---------

Co-authored-by: Onur <[email protected]>

* docs(telegram): recommend allowlist for single-user DM policy (#34841)

* docs(telegram): recommend allowlist for single-user bots

* docs(telegram): condense single-user allowlist note

---------

Co-authored-by: echoVic <[email protected]>

* fix(feishu): check response.ok before calling response.json() in streaming card (#35628)

Merged via squash.

Prepared head SHA: 62c3fec80d97cea9be344c0bef5358a0a5dc5560
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* Mattermost: honor onmessage mention override and add gating diagnostics tests (#27160)

Merged via squash.

Prepared head SHA: 6cefb1d5bf3d6dfcec36c1cee3f9ea887f10c890
Co-authored-by: turian <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm

* fix(subagents): strip leaked [[reply_to]] tags from completion announces (#34503)

* fix(subagents): strip reply tags from completion delivery text

* test(subagents): cover reply-tag stripping in cron completion sends

* changelog: note iMessage reply-tag stripping in completion announces

* Update CHANGELOG.md

* Apply suggestion from @greptile-apps[bot]

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix(cron): restore direct fallback after announce failure in best-effort mode (openclaw#36177)

Verified:
- pnpm build
- pnpm check (fails on pre-existing origin/main lint debt in extensions/mattermost imports)
- pnpm test:macmini

Co-authored-by: Tak Hoffman <[email protected]>

* test(cron): add cross-channel announce fallback regression coverage (openclaw#36197)

Verified:
- pnpm install --frozen-lockfile
- pnpm build
- pnpm check (fails on pre-existing origin/main lint debt in extensions/mattermost imports)
- pnpm test:macmini

Co-authored-by: Tak Hoffman <[email protected]>

* feat(mattermost): add interactive buttons support (#19957)

Merged via squash.

Prepared head SHA: 8a25e608729d0b9fd07bb0ee4219d199d9796dbe
Co-authored-by: tonydehnke <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm

* fix(browser): remove deprecated --disable-blink-features=AutomationControlled flag

- Removes OpenClaw's default `--disable-blink-features=AutomationControlled` Chrome launch switch to avoid unsupported-flag warnings in newer Chrome (#35721).
- Preserves compatibility for older Chrome via `browser.extraArgs` override behavior (source analysis: #35770, #35728, #35727, #35885).
- Synthesis attribution: thanks @Sid-Qin, @kevinWangSheng, @ningding97, @Naylenv, @clawbie.

Source PR refs: #35734, #35770, #35728, #35727, #35885

Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: kevinWangSheng <[email protected]>
Co-authored-by: ningding97 <[email protected]>
Co-authored-by: Naylenv <[email protected]>
Co-authored-by: clawbie <[email protected]>
Co-authored-by: Takhoffman <[email protected]>

* fix(feishu): add HTTP timeout to prevent per-chat queue deadlocks (#36430)

When the Feishu API hangs or responds slowly, the sendChain never settles,
causing the per-chat queue to remain in a processing state forever and
blocking all subsequent messages in that thread. This adds a 30-second
default timeout to all Feishu HTTP requests by providing a timeout-aware
httpInstance to the Lark SDK client.

Closes #36412

Co-authored-by: Ayane <[email protected]>

* fix(feishu): use probed botName for mention checks (#36391)

* Feishu: honor bot mentions by ID despite aliases (Fixes #36317) (#36333)

* Mattermost: switch plugin-sdk imports to scoped subpaths (openclaw#36480)

Verified:
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: Takhoffman <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(feishu): accept groupPolicy "allowall" as alias for "open" (#36358)

* fix(feishu): accept groupPolicy "allowall" as alias for "open"

When users configure groupPolicy: "allowall" in Feishu channel config,
the Zod schema rejects the value and the runtime policy check falls
through to the allowlist path.  With an empty allowFrom array, all group
messages are silently dropped despite the intended "allow all" semantics.

Accept "allowall" at the schema level (transform to "open") and add a
runtime guard in isFeishuGroupAllowed so the value is handled even if it
bypasses schema validation.

Closes #36312

Made-with: Cursor

* Feishu: tighten allowall alias handling and coverage

---------

Co-authored-by: Tak Hoffman <[email protected]>

* synthesis: fix Feishu group mention slash parsing

## Summary\n\nFeishu group slash command parsing is fixed for mentions and command probes across authorization paths.\n\nThis includes:\n- Normalizing bot mention text in group context for reliable slash detection in message parsing.\n- Adding command-probe normalization for group slash invocations.\n\nCo-authored-by: Sid Qin <[email protected]>\nCo-authored-by: Tak Hoffman <[email protected]>

* Feishu: normalize group slash command probing

- Feishu/group slash command detection: normalize group mention wrappers before command-authorization probing so mention-prefixed commands are recognized in group routing.\n- Source PR: #36011\n- Contributor: @liuxiaopai-ai\n\nCo-authored-by: Tak Hoffman <[email protected]>\nCo-authored-by: liuxiaopai-ai <[email protected]>

* add prependSystemContext and appendSystemContext to before_prompt_build (fixes #35131) (#35177)

Merged via squash.

Prepared head SHA: d9a2869ad69db9449336a2e2846bd9de0e647ac6
Co-authored-by: maweibin <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(feishu): avoid media regressions from global HTTP timeout (#36500)

* fix(feishu): avoid media regressions from global http timeout

* fix(feishu): source HTTP timeout from config

* fix(feishu): apply media timeout override to image uploads

* fix(feishu): invalidate cached client when timeout changes

* fix(feishu): clamp timeout values and cover image download

* Gateway: add SecretRef support for gateway.auth.token with auth-mode guardrails (#35094)

* fix(embedded): classify model_context_window_exceeded as context overflow, trigger compaction (#35934)

Merged via squash.

Prepared head SHA: 20fa77289c80b2807a6779a3df70440242bc18ca
Co-authored-by: RealKai42 <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(agents): skip compaction API call when session has no real messages (#36451)

Merged via squash.

Prepared head SHA: 52dd6317895c7bd10855d2bd7dbbfc2f5279b68e
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(ui): catch marked.js parse errors to prevent Control UI crash (#36445)

- Prevent Control UI session render crashes when `marked.parse()` encounters pathological recursive markdown by safely falling back to escaped `<pre>` output.
- Tighten markdown fallback regression coverage and keep changelog attribution in sync for this crash-hardening path.

Co-authored-by: Bin Deng <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(session): archive old transcript on daily/scheduled reset to prevent orphaned files (#35493)

Merged via squash.

Prepared head SHA: 0d95549d752adecfc0b08d5cd55a8b8c75e264fe
Co-authored-by: byungsker <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(agents): set preserveSignatures to isAnthropic in resolveTranscriptPolicy (#32813)

Merged via squash.

Prepared head SHA: f522d21ca59a42abac554435a0aa646f6a34698d
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix: avoid false global rate-limit classification from generic cooldown text (#32972)

Merged via squash.

Prepared head SHA: 813c16f5afce415da130a917d9ce9f968912b477
Co-authored-by: stakeswky <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* refactor(agents): share failover HTTP status classification (#36615)

* fix(agents): classify transient failover statuses consistently

* fix(agents): preserve legacy failover status mapping

* fix(failover): narrow service-unavailable to require overload indicator (#32828) (#36646)

Merged via squash.

Prepared head SHA: 46fb4306127972d7635f371fd9029fbb9baff236
Co-authored-by: jnMetaCode <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* Compaction/Safeguard: add summary quality audit retries (#25556)

Merged via squash.

Prepared head SHA: be473efd1635616ebbae6e649d542ed50b4a827f
Co-authored-by: rodrigouroz <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* test(agents): add provider-backed failover regressions (#36735)

* test(agents): add provider-backed failover fixtures

* test(agents): cover more provider error docs

* test(agents): tighten provider doc fixtures

* Docs: add Slack typing reaction fallback

* Docs: update gateway config reference for Slack and TTS

* Docs: clarify OpenAI-compatible TTS endpoints

* Docs: document Control UI locale support

* Docs: cover heartbeat, cron, and plugin route updates

* fix(ui): bump dompurify to 3.3.2 (#36781)

* UI: bump dompurify to 3.3.2

* Deps: refresh dompurify lockfile

* UI: hoist lifecycle connect test mocks (#36788)

* fix(agents): classify insufficient_quota 400s as billing (#36783)

* feat: append UTC time alongside local time in shared Current time lines (#32423)

Merged via squash.

Prepared head SHA: 9e8ec13933b5317e7cff3f0bc048de515826c31a
Co-authored-by: jriff <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix(auth): grant senderIsOwner for internal channels with operator.admin scope (openclaw#35704)

Verified:
- pnpm install --frozen-lockfile
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: Naylenv <[email protected]>
Co-authored-by: Octane0411 <[email protected]>
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(config): prevent RangeError in merged schema cache key generation

Fix merged schema cache key generation for high-cardinality plugin/channel metadata by hashing incrementally instead of serializing one large aggregate string.

Includes changelog entry for the user-visible regression fix.

Co-authored-by: Tak Hoffman <[email protected]>
Co-authored-by: Bill <[email protected]>

* fix(slack): propagate mediaLocalRoots through Slack send path

Restore Slack local file upload parity with CVE-era local media allowlist enforcement by threading `mediaLocalRoots` through the Slack send call chain.

- pass `ctx.mediaLocalRoots` from Slack channel action adapter into `handleSlackAction`
- add and forward `mediaLocalRoots` in Slack action context/send path
- pass `mediaLocalRoots` into `sendMessageSlack` for upload allowlist enforcement
- add changelog entry with attribution for this behavior fix

Co-authored-by: 2233admin <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(slack): preserve dedupe while recovering dropped app_mention (#34937)

This PR fixes Slack mention loss without reintroducing duplicate dispatches.

- Preserve seen-message dedupe at ingress to prevent duplicate processing.
- Allow a one-time app_mention retry only when the paired message event was previously dropped before dispatch.
- Add targeted race tests for both recovery and duplicate-prevention paths.

Co-authored-by: littleben <[email protected]>
Co-authored-by: OpenClaw Agent <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* README: add algal to contributors list (#2046)

* fix: decouple Discord inbound worker timeout from listener timeout (#36602) (thanks @dutifulbob) (#36602)

Co-authored-by: Onur Solmaz <[email protected]>

* plugins: enforce prompt hook policy with runtime validation (#36567)

Merged via squash.

Prepared head SHA: 6b9d883b6ae33628235fb02ce39c0d0f46a065bb
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(memory): avoid destructive qmd collection rebinds

* Harden Telegram poll gating and schema consistency (#36547)

Merged via squash.

Prepared head SHA: f77824419e3d166f727474a9953a063a2b4547f2
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(browser): close tracked tabs on session cleanup (#36666)

* Diffs: restore system prompt guidance (#36904)

Merged via squash.

Prepared head SHA: 1b3be3c87957c068473d5c86b9efba4a1a8503f2
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* fix(routing): avoid full binding rescans in resolveAgentRoute (#36915)

* fix(gateway): honor insecure ws override for remote hostnames

* fix(llm-task): load runEmbeddedPiAgent from dist/extensionAPI in installs

* fix(auth): harden openai-codex oauth login path

* feat(telegram/acp): Topic Binding, Pin Binding Message, Fix Spawn Param Parsing (#36683)

* fix(acp): normalize unicode flags and Telegram topic binding

* feat(telegram/acp): restore topic-bound ACP and session bindings

* fix(acpx): clarify permission-denied guidance

* feat(telegram/acp): pin spawn bind notice in topics

* docs(telegram): document ACP topic thread binding behavior

* refactor(reply): share Telegram conversation-id resolver

* fix(telegram/acp): preserve bound session routing semantics

* fix(telegram): respect binding persistence and expiry reporting

* refactor(telegram): simplify binding lifecycle persistence

* fix(telegram): bind acp spawns in direct messages

* fix: document telegram ACP topic binding changelog (#36683) (thanks @huntharo)

---------

Co-authored-by: Onur <[email protected]>

* fix(gateway): preserve streamed prefixes across tool boundaries

* fix(tui): prevent stale model indicator after /model

* Memory: handle SecretRef keys in doctor embeddings (#36835)

Merged via squash.

Prepared head SHA: c1a3d0caae60115d886e8bfc9983c9533c773f04
Co-authored-by: joshavant <[email protected]>
Co-authored-by: joshavant <[email protected]>
Reviewed-by: @joshavant

* fix(openai-codex): request required oauth api scopes (#24720)

* fix(memory-flush): ban timestamped variant files in default flush prompt (#34951)

Merged via squash.

Prepared head SHA: efadda4988b460e6da07be72994d4951d64239d0
Co-authored-by: zerone0x <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(tui): render final event error when assistant output is empty (#14687)

* feat(agents): flush reply pipeline before compaction wait (#35489)

Merged via squash.

Prepared head SHA: 7dbbcc510b74b0e8d35eb750d24575e34b5d769a
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix(secrets): harden api key normalization for ByteString headers

* fix(slack): remove double mrkdwn conversion in native streaming path

Remove redundant text normalization from Slack native streaming markdown_text flow so Markdown formatting is preserved.

Synthesis context: overlaps reviewed from #34931, #34759, #34716, #34682, #34814.

Co-authored-by: littleben <[email protected]>
Co-authored-by: dunamismax <[email protected]>
Co-authored-by: Octane <[email protected]>
Co-authored-by: Mitsuyuki Osabe <[email protected]>
Co-authored-by: Kai <[email protected]>
Co-authored-by: OpenClaw Agent <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(kimi-coding): normalize anthropic tool payload format

* fix(slack): thread channel ID through inbound context for reactions (#34831)

Slack reaction/thread context routing fixes via canonical synthesis of #34831.

Co-authored-by: Tak <[email protected]>

* fix(heartbeat): pin HEARTBEAT.md reads to workspace path

* fix(subagents): recover announce cleanup after kill/complete race

* feat(hooks): emit compaction lifecycle hooks (#16788)

* fix(auth): harden openai-codex oauth refresh fallback

* fix(subagents): announce delivery with descendant gating, frozen result refresh, and cron retry (#35080)

Thanks @tyler6204

* fix(agents): avoid synthetic tool-result writes on idle-timeout cleanup

* fix(agent): harden undici stream timeouts for long openai-completions runs

* fix(slack): record app_mention retry key before dedupe check (#37033)

- Prime app_mention retry allowance before dedupe so near-simultaneous message/app_mention races do not drop valid mentions.
- Prevent duplicate dispatch when app_mention wins the race and message prepare later succeeds.
- Prune dispatched mention keys and add regression coverage for both dropped and successful in-flight message outcomes.

Co-authored-by: Tak Hoffman <[email protected]>

* fix(agents): honor explicit rate-limit cooldown probes in fallback runs

* fix(agents): allow configured ollama endpoints without dummy api keys

* fix(memory): recover qmd updates from duplicate document constraints

* Doctor: warn on implicit heartbeat directPolicy (#36789)

* Changelog: note heartbeat directPolicy doctor warning

* Tests: cover heartbeat directPolicy doctor warning

* Doctor: warn on implicit heartbeat directPolicy

* Tests: cover per-agent heartbeat directPolicy warning

* Update CHANGELOG.md

* Plugins: clarify registerHttpHandler migration errors (#36794)

* Changelog: note plugin HTTP route migration diagnostics

* Tests: cover registerHttpHandler migration diagnostics

* Plugins: clarify registerHttpHandler migration errors

* Tests: cover registerHttpHandler diagnostic edge cases

* Plugins: tighten registerHttpHandler migration hint

* fix(memory): repair qmd collection name conflicts during ensure

* fix(memory): handle qmd search results without docid

* Plugins: avoid false integrity drift prompts on unpinned updates (#37179)

* Plugins: skip drift prompts for unpinned updates

* Plugins: cover unpinned integrity update behavior

* Changelog: add #37179 release note

* Delete changelog/fragments directory

* Update CHANGELOG.md

* fix(whatsapp): remove implicit [openclaw] self-chat prefix

* fix: remove config.schema from agent gateway tool (#7382)

Merged via squash.

Prepared head SHA: f34a7780690a941936b31899e2d096b8a07f4afc
Co-authored-by: kakuteki <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* feat(openai): add gpt-5.4 support for API and Codex OAuth (#36590)

* feat(openai): add gpt-5.4 support and priority processing

* feat(openai-codex): add gpt-5.4 oauth support

* fix(openai): preserve provider overrides in gpt-5.4 fallback

* fix(openai-codex): keep xhigh for gpt-5.4 default

* fix(models): preserve configured overrides in list output

* fix(models): close gpt-5.4 integration gaps

* fix(openai): scope service tier to public api

* fix(openai): complete prep followups for gpt-5.4 support (#36590) (thanks @dorukardahan)

---------

Co-authored-by: Tyler Yust <[email protected]>

* fix(tui): preserve credential-like tokens in render sanitization

* CLI: make read-only SecretRef status flows degrade safely (#37023)

* CLI: add read-only SecretRef inspection

* CLI: fix read-only SecretRef status regressions

* CLI: preserve read-only SecretRef status fallbacks

* Docs: document read-only channel inspection hook

* CLI: preserve audit coverage for read-only SecretRefs

* CLI: fix read-only status account selection

* CLI: fix targeted gateway fallback analysis

* CLI: fix Slack HTTP read-only inspection

* CLI: align audit credential status checks

* CLI: restore Telegram read-only fallback semantics

* chore(changelog): update for #37023

Signed-off-by: joshavant <[email protected]>

* fix(agents): disable usage streaming chunks on non-native openai-completions

* feat(nano-banana-pro): add --aspect-ratio flag to generate_image.py (#28159)

* feat(nano-banana-pro): add --aspect-ratio flag to generate_image.py

* Nano Banana: allow all supported aspect ratios

* Docs: expand nano banana aspect ratio options

---------

Co-authored-by: Vincent Koc <[email protected]>

* fix(gateway): support image_url in OpenAI chat completions (#34068)

* fix(gateway): parse image_url in openai chat completions

* test(gateway): cover openai chat completions image_url flows

* docs(changelog): note openai image_url chat completions fix (#17685)

* fix(gateway): harden openai image_url parsing and limits

* test(gateway): add openai image_url regression coverage

* docs(changelog): expand #17685 openai chat completions note

* Gateway: make OpenAI image_url URL fetch opt-in and configurable

* Diagnostics: redact image base64 payload data in trace logs

* Changelog: note OpenAI image_url hardening follow-ups

* Gateway: enforce OpenAI image_url total budget incrementally

* Gateway: scope OpenAI image_url extraction to the active turn

* Update CHANGELOG.md

* fix(agents): avoid xAI web_search tool-name collisions

* fix: clear Telegram DM draft after materialize (#36746) (thanks @joelnishanth)

* Fix Control UI duplicate iMessage replies for internal webchat turns (#36151)

* Auto-reply: avoid routing external replies from internal webchat turns

* Auto-reply tests: cover internal webchat non-routing with external origin metadata

* Changelog: add Control UI iMessage duplicate-reply fix note

* Auto-reply context: track explicit deliver routes

* Gateway chat: mark explicit external deliver routes in context

* Auto-reply: preserve explicit deliver routes for internal webchat turns

* Auto-reply tests: cover explicit deliver routes from internal webchat turns

* Gateway chat tests: assert explicit deliver route context tagging

* fix: enforce 600 perms for cron store and run logs (#36078)

* fix: enforce secure permissions for cron store and run logs

* fix(cron): enforce dir perms and gate posix tests on windows

* Cron store tests: cover existing directory permission hardening

* Cron run-log tests: cover existing directory permission hardening

* Changelog: note cron file permission hardening

---------

Co-authored-by: linhey <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>

* fix(tui): accept canonical session-key aliases in chat event routing

* Gateway: normalize OpenAI stream chunk text

* Gateway: coerce chat deliverable route boolean

* fix(web_search): align brave language codes with API

* Respect source channel for agent event surfacing (#36030)

* fix(session): prefer webchat routes for direct ui turns (#37135)

* Gateway: discriminate input sources

* Cron: migrate legacy provider delivery hints

* Cron: stabilize runs-one-shot migration tests

* fix(memory): retry mcporter after Windows EINVAL spawn

* fix(onboarding): guard daemon status probe on headless linux

* Gateway: add path-scoped config schema lookup (#37266)

Merged via squash.

Prepared head SHA: 0c4d187f6fb66f2799d4047585d6368e433c883a
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Reviewed-by: @gumadeiras

* docs(changelog): add pr entry

* fix(ci): restore protocol and schema checks (#37470)

* Fix failover for zhipuai 1310 Weekly/Monthly Limit Exhausted (#33813)

Merged via squash.

Prepared head SHA: 3dc441e58de48913720cf7b6137fa761758d8344
Co-authored-by: zhouhe-xydt <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Reviewed-by: @altaywtf

* fix(openai-codex-oauth): stop mutating authorize url scopes

* Update CHANGELOG.md

* fix(auth): remove bogus codex oauth responses probe

* docs(changelog): fold codex oauth fix notes

* docs(changelog): add codex oauth pr reference (#37558)

* fix(security:PLA-697): block local secret scratch files from commits

* feat: add dev EKS deployment for openclaw SRE container

* fix: stabilize slack socket mode in dev eks runtime

* fix(eks): reuse monitoring incident auth for openclaw-sre

* feat(deploy): add grafana env guards and prod deploy wrapper

* fix(security): redact tool outputs and enforce secret-safe runtime defaults

* feat(sre): harden heartbeat routing and enrich triage signals

* docs: add SRE hybrid intelligence design

Three-layer architecture to improve bot reasoning quality:
- Layer 1: Service knowledge (auto-discovery + overlays + incident memory)
- Layer 2: Multi-stage reasoning chain (triage → hypothesize → causal chain → action plan → cross-review)
- Layer 3: Incident learning loop (structured cards, overlay suggestions, feedback signals)

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* feat(sandbox): add boundary cli to common runtime image

* docs(sre): finalize hybrid intelligence design v19 after 18 Codex review rounds

Iteratively hardened the design through 18 adversarial Codex review rounds,
resolving 60+ findings (15+ CRITICAL, 45+ HIGH). Key fixes include:
- Decoupled incident_id (pre-Step11 immutable) from card_id (LLM-derived)
- Unified evidence/memory sanitization via shared _strip_instruction_tokens
- Fixed rerun interval default (3600s > heartbeat 1800s) to prevent every-cycle re-runs
- Added Phase 2 cross-review gap note and dual-column depth table
- Overlay suggestion idempotency via deterministic suggestion_key + upsert
- Decoupled chain timeout from legacy budget check
- Added predicate alignment docs for L3 pre-check vs L3 gate
- Adopted dynamic evidence_completeness denominator matching existing code
- Added scope note clarifying design vs current implementation

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* feat(sre): complete hybrid intelligence rollout and bot hardening

* fix(sre): harden slack reasoning, dual chain, and deploy auth/runtime

* ci: add ecr release pipeline and infra-helm image update trigger

* ci: switch workflows to github-hosted runners

* ci: allow manual ecr env target and use updater v4

* ci: remove windows jobs from workflow

* chore(pla-678): update fallback auth fixture and plan docs

* fix(pla-678): preserve control-ui host-header fallback in dev config

* refactor(pla-678): remove local sre chart and require infra-helm

* refactor(pla-678): remove direct eks deploy scripts

* ci(pla-678): remove labeler workflow

* ci(pla-678): refresh checks after disabling labeler

* build: install boundary CLI in SRE runtime image

* fix(slack:PLA-678): keep one thread lane across users

* fix(sre-skill): enforce live db-query runbook in dev seed

* fix(slack): ignore bot thread history when seeding new sessions

* fix(slack): force retry on repeated thread questions

* fix(sre-skill): require retry on repeated db requests

* docs(sre-skill): make retry policy generic across repeated asks

* fix(sre:PLA-678): enforce live linear ticket updates

* fix(sre:PLA-678): use [PLATFORM] Backlog linear project

* fix(sre:PLA-678): label linked linear tickets as openclaw-sre

* fix(sre:PLA-678): auto-label linked linear tickets for auto-pr

* test(sre:PLA-678): make tracking label test executable

* fix(slack:PLA-678): remove status-final completion banner (#16)

* fix(slack:PLA-678): enable direct file attachments from agent replies (#17)

* fix(slack:PLA-678): remove status-final completion banner

* fix(slack): enable direct file attachments from agent replies

* refactor(sre:PLA-678): remove local deploy config mirror (#18)

* fix: compact oversized auto-generated pr bodies

* fix(sre): add built-in linear incident memory provider

* feat(sre): add erpc helper with flo secret query

* fix(sre): enforce canonical rpc.morpho.dev erpc endpoint

* refactor(sre): remove local deploy config mirror

* fix(slack:PLA-678): force DM replies into per-message threads (#19)

* fix: compact oversized auto-generated pr bodies

* fix(sre): add built-in linear incident memory provider

* feat(sre): add erpc helper with flo secret query

* fix(sre): enforce canonical rpc.morpho.dev erpc endpoint

* refactor(sre): remove local deploy config mirror

* fix(slack): force threaded replies for direct messages

* feat(cron:PLA-678): use conversation history in self-improve runs (#20)

* fix(slack:PLA-678): improve progress update readability (#21)

* fix(ci:PLA-678): restore main release pipeline health (#22)

* fix(ci:PLA-678): restore main release pipeline health

* fix(ci:PLA-678): harden auto-response token fallback

* fix(ci:PLA-678): pin setup-bun to published release

* test(ci:PLA-678): align slack thread session expectations

* fix(sre:PLA-678): harden Slack reply delivery and image release flow (#23)

* fix(slack:PLA-678): harden thread-scoped reply delivery

* fix(slack:PLA-678): satisfy lint after rebase

* ci(release:PLA-678): move image release to cached ecr flow

* ci(release:PLA-678): use official docker build actions

* fix(slack:PLA-722): preserve progress updates during final-answer gating (#24)

* fix(sre:PLA-724): restore ECR runtime image toolchain (#25)

* fix(failover): classify HTTP 402 as rate_limit when payload indicates usage limit (#30484) (#36802)

* fix(failover): classify HTTP 402 as rate_limit when payload indicates usage limit (#30484)

Some providers (notably Anthropic Claude Max plan) surface temporary
usage/rate-limit failures as HTTP 402 instead of 429. Before this change,
all 402s were unconditionally mapped to 'billing', which produced a
misleading 'run out of credits' warning for Max plan users who simply
hit their usage window.

This follows the same pattern introduced for HTTP 400 in #36783: check
the error message for an explicit rate-limit signal before falling back
to the default status-code classification.

- classifyFailoverReasonFromHttpStatus now returns 'rate_limit' for 402
  when isRateLimitErrorMessage matches the payload text
- Added regression tests covering both the rate-limit and billing paths
  on 402

* fix: narrow 402 rate-limit matcher to prevent billing misclassification

The original implementation used isRateLimitErrorMessage(), which matches
phrases like 'quota exceeded' that legitimately appear in billing errors.

This commit replaces it with a narrow, 402-specific matcher that requires
BOTH retry language (try again/retry/temporary/cooldown) AND limit
terminology (usage limit/rate limit/organization usage).

Prevents misclassification of errors like:
'HTTP 402: exceeded quota, please add credits' -> billing (not rate_limit)

Added regression test for the ambiguous case.

---------

Co-authored-by: Val Alexander <[email protected]>

* fix(mattermost): allow reachable interaction callback URLs (#37543)

Merged via squash.

Prepared head SHA: 4d593731be5a5dcbf3106d596b38acfeb8cf0aa8
Co-authored-by: mukhtharcm <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm

* fix(auth): prefer Anthropic API key over stale OAuth profiles

* fix(runtime): raise default agent timeout to one hour

* feat(runtime): support direct env fallback for agent timeout

---------

Signed-off-by: joshavant <[email protected]>
Co-authored-by: Gustavo Madeira Santana <[email protected]>
Co-authored-by: Mariano <[email protected]>
Co-authored-by: leepokai <[email protected]>
Co-authored-by: Bob <[email protected]>
Co-authored-by: Onur <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
Co-authored-by: huangcj <[email protected]>
Co-authored-by: gumadeiras <[email protected]>
Co-authored-by: Sid <[email protected]>
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: shakkernerd <[email protected]>
Co-authored-by: a <[email protected]>
Co-authored-by: echoVic <[email protected]>
Co-authored-by: Shakker <[email protected]>
Co-authored-by: liuxiaopai-ai <[email protected]>
Co-authored-by: Rodrigo Uroz <[email protected]>
Co-authored-by: rodrigouroz <[email protected]>
Co-authored-by: jalehman <[email protected]>
Co-authored-by: Kai <[email protected]>
Co-authored-by: RealKai42 <[email protected]>
Co-authored-by: 青雲 <[email protected]>
Co-authored-by: echoVic <[email protected]>
Co-authored-by: Darshil <[email protected]>
Co-authored-by: Ho Lim <[email protected]>
Co-authored-by: dvrshil <[email protected]>
Co-authored-by: Isis Anisoptera <[email protected]>
Co-authored-by: Madoka <[email protected]>
Co-authored-by: Xu Zimo <[email protected]>
Co-authored-by: Munem Hashmi <[email protected]>
Co-authored-by: bmendonca3 <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>
Co-authored-by: Nhj <[email protected]>
Co-authored-by: 倪汉杰0668001185 <[email protected]>
Co-authored-by: zhengquanliu <[email protected]>
Co-authored-by: nick <[email protected]>
Co-authored-by: linhey <[email protected]>
Co-authored-by: scoootscooob <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: rexl2018 <[email protected]>
Co-authored-by: sline <[email protected]>
Co-authored-by: 0xsline <[email protected]>
Co-authored-by: Harold Hunt <[email protected]>
Co-authored-by: Shivam <[email protected]>
Co-authored-by: 不做了睡大觉 <[email protected]>
Co-authored-by: alexyyyander <[email protected]>
Co-authored-by: alexyyyander <[email protected]>
Co-authored-by: Octane0411 <[email protected]>
Co-authored-by: Linux2010 <[email protected]>
Co-authored-by: echoVic <[email protected]>
Co-authored-by: Joseph Turian <[email protected]>
Co-authored-by: turian <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Tony Dehnke <[email protected]>
Co-authored-by: Sid-Qin <[email protected]>
Co-authored-by: kevinWangSheng <[email protected]>
Co-authored-by: ningding97 <[email protected]>
Co-authored-by: Naylenv <[email protected]>
Co-authored-by: clawbie <[email protected]>
Co-authored-by: Takhoffman <[email protected]>
Co-authored-by: Ayane <[email protected]>
Co-authored-by: Ayane <[email protected]>
Co-authored-by: StingNing <[email protected]>
Co-authored-by: maweibin <[email protected]>
Co-authored-by: maweibin <[email protected]>
Co-authored-by: Josh Avant <[email protected]>
Co-authored-by: Bin Deng <[email protected]>
Co-authored-by: Byungsker <[email protected]>
Co-authored-by: altaywtf <[email protected]>
Co-authored-by: Altay <[email protected]>
Co-authored-by: jiangnan <[email protected]>
Co-authored-by: jnMetaCode <[email protected]>
Co-authored-by: Jacob Riff <[email protected]>
Co-authored-by: jriff <[email protected]>
Co-authored-by: Naylenv <[email protected]>
Co-authored-by: Bill <[email protected]>
Co-authored-by: 2233admin <[email protected]>
Co-authored-by: 2233admin <[email protected]>
Co-authored-by: littleben <[email protected]>
Co-authored-by: littleben <[email protected]>
Co-authored-by: OpenClaw Agent <[email protected]>
Co-authored-by: Vignesh Natarajan <[email protected]>
Co-authored-by: zerone0x <[email protected]>
Co-authored-by: zerone0x <[email protected]>
Co-authored-by: dunamismax <[email protected]>
Co-authored-by: Octane <[email protected]>
Co-authored-by: Mitsuyuki Osabe <[email protected]>
Co-authored-by: Tak <[email protected]>
Co-authored-by: Tyler Yust <[email protected]>
Co-authored-by: Hinata Kaga (samon) <[email protected]>
Co-authored-by: dorukardahan <[email protected]>
Co-authored-by: Tyler Yust <[email protected]>
Co-authored-by: Brenner Spear <[email protected]>
Co-authored-by: aerelune <[email protected]>
Co-authored-by: Frank Yang <[email protected]>
Co-authored-by: zhouhe-xydt <[email protected]>
Co-authored-by: zhouhe-xydt <[email protected]>
Co-authored-by: Vignesh <[email protected]>
Co-authored-by: OpenClaw SRE Bot <[email protected]>
Co-authored-by: Xinhua Gu <[email protected]>
Co-authored-by: Val Alexander <[email protected]>
kurock09 added a commit to kurock09/openclaw that referenced this pull request Apr 1, 2026
…ntime

getTtsProvider() never saw PersAI admin provider choice (yandex/elevenlabs)
because it read from config file or prefs file, neither populated by PersAI.
With OPENAI_API_KEY globally available, it always defaulted to openai.

- Add toolProviderOverrides to PersaiRuntimeRequestCtx
- Extract providerId from bootstrap toolCredentialRefs in all HTTP handlers
- getTtsProvider() now checks PersAI context first (highest priority)
- Add YANDEX_TTS_API_KEY to primary lookup in resolveTtsApiKey + yandex provider
- 2 new tests, patch openclaw#22, verify script updated (97/97)

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants