fix: pass sessionKey to deliverOutboundPayloads for message:sent hook dispatch#27584
Merged
steipete merged 2 commits intoopenclaw:mainfrom Feb 26, 2026
Merged
Conversation
Contributor
Greptile SummaryFixes
All changes correctly source the sessionKey from their respective function parameters/contexts. Confidence Score: 5/5
Last reviewed commit: 70e4b97 |
70e4b97 to
e6afbb5
Compare
steipete
added a commit
to qualiobra/openclaw
that referenced
this pull request
Feb 26, 2026
… dispatch Several call sites of deliverOutboundPayloads() were not passing the sessionKey parameter, causing the internal message:sent hook to never fire (the guard `if (!sessionKeyForInternalHooks) return` in deliver.ts silently skipped the triggerInternalHook call). Fixed call sites: - commands/agent/delivery.ts (agent loop replies — main fix) - infra/heartbeat-runner.ts (heartbeat OK + alert delivery) - infra/outbound/message.ts (message tool sends) - cron/isolated-agent/delivery-dispatch.ts (cron job delivery) - gateway/server-node-events.ts (node event forwarding) The sessionKey parameter already existed in DeliverOutboundPayloadsCoreParams and was used by deliver.ts to emit the message:sent internal hook event, but was simply not being passed from most callers.
e6afbb5 to
fbde02d
Compare
Contributor
|
Landed via temp rebase onto main.
Thanks @qualiobra! |
steipete
added a commit
that referenced
this pull request
Feb 26, 2026
…by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local>
Contributor
|
Follow-up landing complete on top of latest What we did:
SHA hashes:
Thanks again @qualiobra for the original fix and context. |
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 27, 2026
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 27, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local>
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 27, 2026
…7584) (thanks @qualiobra) (cherry picked from commit 24b399b)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 27, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local> (cherry picked from commit e733b89)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 27, 2026
…7584) (thanks @qualiobra) (cherry picked from commit 24b399b)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 27, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local> (cherry picked from commit e733b89)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 27, 2026
…7584) (thanks @qualiobra) (cherry picked from commit 24b399b)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 27, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local> (cherry picked from commit e733b89)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 27, 2026
…7584) (thanks @qualiobra) (cherry picked from commit 24b399b)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 27, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local> (cherry picked from commit e733b89)
KrD-Hub
added a commit
to KrD-Hub/openclaw
that referenced
this pull request
Feb 27, 2026
* Secrets migrate: share helpers and narrow env scrub scope * Secrets migrate: ensure unique backup ids per write * Agents: restore auth.json static scrub during pi auth discovery * Secrets migrate: split plan/apply/backup modules * Onboard: persist env-backed API keys as secret refs * Onboard auth: use shared secret-ref helpers * Auth choice tests: assert env-backed keyRef persistence * Auth choice tests: expect env-backed key refs * Onboard: require explicit mode for env secret refs * Tests: align auth-choice helper expectations with secret mode * Tests: update onboard credential expectations for explicit ref mode * Onboard: store OpenAI auth in profiles instead of .env * Tests: narrow OpenAI default model assertion typing * Onboard auth: remove leftover merge marker * Onboard OpenAI: explicit secret-input-mode behavior * Onboard: move volcengine/byteplus auth from .env to profiles * Onboard non-interactive: avoid rewriting profile-backed keys * Secrets: keep read-only runtime sync in-memory * Onboard: require explicit mode for env secret refs * Docs: document secrets refs runtime and migration * Docs: add secrets and CLI secrets reference pages * Docs: address review feedback on secrets docs * feat(secrets): finalize external secrets runtime and migration hardening * fix(secrets): harden sops migration sops rule matching * feat(secrets): expand onboarding secret-ref flows and custom-provider parity * test: sops invocation assertion Signed-off-by: joshavant <830519+joshavant@users.noreply.github.com> * feat(security): add provider-based external secrets management * docs(secrets): align provider model and add exec resolver coverage * test(secrets): skip strict file-permission resolver tests on windows * test(secrets): skip windows ACL-sensitive file-provider runtime tests * test(session): normalize parent fork parentSession path assertion * fix(secrets): enforce file provider read timeouts * fix(secrets): align ref contracts and non-interactive ref persistence * feat(secrets): replace migrate flow with audit/configure/apply * fix(secrets): make apply idempotent and keep audit read-only * feat(secrets): finalize mode rename and validated exec docs * feat(secrets): allow opt-in symlink exec command paths * docs(secrets): add direct 1password exec example * fix(secrets): harden apply and audit plan handling * test(secrets): cover skill migration and symlinked exec command flow * docs(secrets): clarify partial migration guidance * fix(test): skip exec-backed audit batching assertion on windows * fix(secrets): harden plan target paths and ref-only auth profiles * docs(secrets): add dedicated apply plan contract page * fix: stabilize secrets land + docs note (openclaw#26155) (thanks @joshavant) * docs(gateway): clarify remote token local fallback semantics * docs(changelog): highlight external secrets management (openclaw#26155) * docs(changelog): reorder unreleased changes by user interest * docs(changelog): reorder all unreleased entries by user impact * fix(browser): land PR openclaw#27617 relay reconnect resilience * fix(ci): sync protocol models and acpx version * fix: tolerate missing pi-coding-agent backend export * fix: detect OpenClaw-managed launchd/systemd services in process respawn restartGatewayProcessWithFreshPid() checks SUPERVISOR_HINT_ENV_VARS to decide whether to let the supervisor handle the restart (mode=supervised) or to fork a detached child (mode=spawned). The existing list only had native launchd vars (LAUNCH_JOB_LABEL, LAUNCH_JOB_NAME) and systemd vars (INVOCATION_ID, SYSTEMD_EXEC_PID, JOURNAL_STREAM). macOS launchd does NOT automatically inject LAUNCH_JOB_LABEL into the child environment. OpenClaw's own plist generator (buildServiceEnvironment in service-env.ts) sets OPENCLAW_LAUNCHD_LABEL instead. So on stock macOS LaunchAgent installs, isLikelySupervisedProcess() returned false, causing the gateway to fork a detached child on SIGUSR1 restart. The original process then exits, launchd sees its child died, respawns a new instance which finds the orphan holding the port — infinite crash loop. Fix: add OPENCLAW_LAUNCHD_LABEL, OPENCLAW_SYSTEMD_UNIT, and OPENCLAW_SERVICE_MARKER to the supervisor hint list. These are set by OpenClaw's own service environment builders for both launchd and systemd and are the reliable supervised-mode signals. Fixes openclaw#27605 * fix: clean stale gateway PIDs before triggerOpenClawRestart calls launchctl/systemctl When the /restart command runs inside an embedded agent process (no SIGUSR1 listener), it falls through to triggerOpenClawRestart() which calls launchctl kickstart -k directly — bypassing the pre-restart port cleanup added in openclaw#27013. If the gateway was started via TUI/CLI, the orphaned process still holds the port and the new launchd instance crash-loops. Add synchronous stale-PID detection (lsof) and termination (SIGTERM→SIGKILL) inside triggerOpenClawRestart() itself, so every caller — including the embedded agent /restart path — gets port cleanup before the service manager restart command fires. Closes openclaw#26736 Made-with: Cursor * feat(agents): default codex transport to websocket-first * chore(deps): refresh grammy and @types/node * fix(gateway): add ThrottleInterval to launchd plist to prevent restart loop * docs(changelog): unify gateway restart-loop fixes * fix(security): centralize dm/group allowlist auth composition * fix(telegram): split stop-created preview finalization path Refactor lane preview finalization into explicit branches so stop-created previews never duplicate sends when edit fails. Add Telegram dispatch regressions for: - stop-created preview edit failure (no duplicate send) - existing preview edit failure (fallback send preserved) - missing message id after stop-created flush (fallback send) Thanks @obviyus for the original preview-prime direction in openclaw#27449. Co-authored-by: Ayaan Zaidi <hi@obviy.us> * fix(security): bind node system.run approvals to env * fix(pi): stop history image reinjection token blowup * refactor(restart): extract stale pid cleanup and supervisor markers * fix(bluebubbles): allow configured host for attachment SSRF guard Co-authored-by: damaozi <1811866786@qq.com> * fix(msteams): Send invokeResponse immediately to prevent Teams timeout (openclaw#27632) Fix file upload 'Something went wrong' error by sending the invoke acknowledgement before performing the file upload, rather than after. Changes: - Move invokeResponse to fire immediately upon receiving fileConsent/invoke - Handle file upload asynchronously without blocking the response - Update test to wait for async upload completion using vi.waitFor This prevents Teams from timing out while waiting for the HTTP 200 acknowledgement during slow file uploads to OneDrive. Fixes openclaw#27632 * fix(msteams): Fix test timing for async file upload handling Update tests to properly wait for async file upload operations: - Use vi.waitFor() to wait for async upload completion in success case - Use vi.waitFor() to wait for error message in cross-conversation case - Add setTimeout delay for decline case to ensure async handler completes - Adjust assertion order to match new execution flow (invokeResponse first) The tests were failing because the file upload now happens asynchronously after sending the invokeResponse, so we need to explicitly wait for the async operations to complete before making assertions. * fix(msteams): Fix code formatting Remove trailing whitespace to pass oxfmt format check. * fix: finalize teams file-consent timeout landing (openclaw#27641) (thanks @scz2011) * refactor: unify channel/plugin ssrf fetch policy and auth fallback * refactor(pi): extract history image prune helpers * docs: add unreleased security note for msteams ssrf hardening * refactor(pi): simplify image reference detection * fix: set authHeader: true by default for MiniMax API provider (openclaw#27622) * Update onboard-auth.config-minimax.ts fix issue openclaw#27600 * fix(minimax): default authHeader for implicit + onboarding providers (openclaw#27600) Landed from contributor PR openclaw#27622 by @riccoyuanft and PR openclaw#27631 by @kevinWangSheng. Includes a small TS nullability guard in lane delivery to keep build green on rebased head. Co-authored-by: riccoyuanft <riccoyuan@gmail.com> Co-authored-by: Kevin Shenghui <shenghuikevin@github.com> --------- Co-authored-by: Peter Steinberger <steipete@gmail.com> Co-authored-by: Kevin Shenghui <shenghuikevin@github.com> * feat(android): add device invoke protocol commands * feat(android): add device status and info handler * feat(android): wire device commands into runtime * refactor(android): remove dead thermal sdk branch * fix(android): require validated network for device status * docs: add changelog for android device node commands (openclaw#27664) (thanks @obviyus) * refactor(exec-approvals): unify system.run binding and generate host env policy * fix: harden typing lifecycle and cross-channel suppression * fix: harden plugin route auth path canonicalization * test(exec-approvals): cover v1 binding precedence and mismatch mapping * Mattermost: avoid raw fetch in monitor media download * protocol: regenerate Swift models for exec env field * refactor: share gateway security path canonicalization * fix(gateway): preserve turn-origin messageChannel in agent runs * refactor: unify typing dispatch lifecycle and policy boundaries * fix(agents): harden compaction and reset safety Co-authored-by: jaden-clovervnd <91520439+jaden-clovervnd@users.noreply.github.com> Co-authored-by: Sid <201593046+Sid-Qin@users.noreply.github.com> Co-authored-by: Marcus Widing <245375637+widingmarcus-cyber@users.noreply.github.com> * test(agents): add compaction and workspace reset regressions * refactor: unify dm policy store reads and reason codes * fix(discord): avoid invalid /acp native option payload * docs(acp): expand /acp operator playbook * add me to Maintainers list Signed-off-by: joshavant <830519+joshavant@users.noreply.github.com> * docs(security): scope obfuscation parity reports as hardening * docs(security): clarify Teams fileConsent uploadUrl report scope * refactor(security): enforce v1 node exec approval binding * feat(auto-reply): make agent time-aware with message timestamps Add human-readable timestamp field to the Conversation info JSON block. Before: { "conversation_label": "D id:123" } After: { "conversation_label": "D id:123", "timestamp": "Sun 2026-02-15 13:35 GMT+8" } Benefits: - Better time awareness for time-related questions - Understand conversation gaps and response delays - Handle delayed message delivery - Context for relative time references ("just now", "later") * test(auto-reply): cover inbound timestamp guard * docs(changelog): add PR openclaw#17017 entry * fix: enforce explicit group auth boundaries across channels * fix: restore dm command and self-chat auth behavior * style: format auth boundary updates * fix(cli): gateway status probe with TLS when bind=lan - Use wss:// scheme when TLS is enabled (specifically for bind=lan) - Load TLS runtime to get certificate fingerprint - Pass fingerprint to probeGatewayStatus for self-signed cert trust * fix(cli): add TLS daemon-status probe regression coverage * fix(cli): scope daemon status TLS fingerprint to local probes * test(cli): tighten daemon status TLS mock typings * fix(cli): list all supported auth modes in gateway run --auth help Made-with: Cursor * fix: align gateway run auth modes (openclaw#27469) (thanks @s1korrrr) * Add contributor Jonathan Taylor to CONTRIBUTING.md Added Jonathan Taylor's contributions and contact links. * fix: add nimrod gutman maintainer profile (openclaw#27840) (thanks @ngutman) * fix: harden dm command authorization in open mode * fix(windows): normalize namespaced path containment checks * refactor(cli): dedupe gateway run mode parsing * fix(config): add openai-codex-responses to ModelApiSchema The config schema validates provider api fields against ModelApiSchema, but openai-codex-responses was missing from the allowed values. This forces users to set api: "openai-responses" for the openai-codex provider, which routes requests to api.openai.com/v1/responses instead of chatgpt.com/backend-api/codex/responses, causing HTTP 401 errors because Codex OAuth tokens lack api.responses.write scope for the standard OpenAI Responses endpoint. The runtime already supports openai-codex-responses throughout: model registry, stream dispatch (streamOpenAICodexResponses), and provider detection (OPENAI_MODEL_APIS set). Only the config schema was missing the literal. * fix: align codex model api schema/type coverage (openclaw#27501) (thanks @AytuncYildizli) * refactor(config): dedupe model api definitions * CI: add maintainer ping auto-response * fix(tui): preserve streamed text during tool call transitions Fixes openclaw#27674 The TUI was erasing already-streamed assistant text when tool calls were triggered. This happened because the finalize() method in TuiStreamAssembler was not using the protectBoundaryDrops option when updating run state. Now finalize() applies the same boundary drop protection as ingestDelta(), ensuring that streamed text before tool calls is preserved when the final payload drops earlier content blocks. * fix: narrow finalize boundary-drop guard (openclaw#27711) (thanks @scz2011) * refactor(tui): simplify stream boundary-drop modes * Changelog: add entries for PR openclaw#12849 and openclaw#27585 (openclaw#27887) * fix(browser): stop wrapping application errors with Can't reach message * fix: pass sessionKey to deliverOutboundPayloads for message:sent hook dispatch Several call sites of deliverOutboundPayloads() were not passing the sessionKey parameter, causing the internal message:sent hook to never fire (the guard `if (!sessionKeyForInternalHooks) return` in deliver.ts silently skipped the triggerInternalHook call). Fixed call sites: - commands/agent/delivery.ts (agent loop replies — main fix) - infra/heartbeat-runner.ts (heartbeat OK + alert delivery) - infra/outbound/message.ts (message tool sends) - cron/isolated-agent/delivery-dispatch.ts (cron job delivery) - gateway/server-node-events.ts (node event forwarding) The sessionKey parameter already existed in DeliverOutboundPayloadsCoreParams and was used by deliver.ts to emit the message:sent internal hook event, but was simply not being passed from most callers. * fix: complete sessionKey forwarding for message:sent hook (openclaw#27584) (thanks @qualiobra) * fix(matrix): preserve sender labels in Matrix BodyForAgent * refactor(matrix): dedupe sender label resolution for inbound bodies * refactor: unify outbound session context wiring * fix(gemini-oauth): align OAuth project discovery metadata and endpoint fallbacks (openclaw#16684) * fix(gemini-oauth): align loadCodeAssist metadata and endpoint fallback * test(gemini-oauth): cover endpoint fallback and env project fallback * fix(gemini-oauth): route timed fetches through ssrf guard * test(gemini-oauth): mock guarded fetch in oauth tests * chore(onboarding): add explicit account-risk warning for Gemini CLI OAuth and docs (openclaw#16683) * docs: add account-risk caution to Google OAuth provider docs * docs(plugin): add Gemini CLI account safety caution * CLI: add risk hint for Gemini CLI auth choice * Onboarding: require confirmation for Gemini CLI OAuth * Tests: cover Gemini CLI OAuth risk confirmation flow * fix(voice-call): bind webhook dedupe to verified request identity * feat(config): add embedded pi project settings policy * fix(agents): harden embedded pi project settings loading * fix(security): harden node exec approvals against symlink rebind * refactor(voice-call): share header and guarded api helpers * refactor(voice-call): enforce verified webhook key contract * test(voice-call): cover verification key and header helpers * docs: enforce repo-relative file refs in AGENTS * refactor(extensions): use scoped pairing helper * refactor(security): enforce account-scoped pairing APIs * refactor(node-host): split system.run plan and allowlist internals * refactor(gateway): share node command catalog * refactor(gateway): centralize system.run approval context and errors * refactor(cli): decompose nodes run approval flow * fix(nodes): resolve default node when multiple canvas-capable nodes are connected `pickDefaultNode()` returned null when multiple connected canvas-capable nodes existed and none matched the local Mac heuristic. This caused "node required" errors for agents (especially sub-agents) calling the canvas tool without an explicit node parameter. In multi-node setups, any canvas-capable node is a valid target — the receiving node broadcasts A2UI surfaces to all other connected devices. Fall back to the first connected candidate instead of failing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add nodes default-node regression test (openclaw#27444) (thanks @carbaj03) * fix(agent): forward resolved outbound session context for delivery * fix(browser): accept fill fields without explicit type Default missing fill field type to 'text' in /act route to avoid spurious 'fields are required' failures from relay/tool callers. Add regression test for fill payloads with ref+value only. * fix: browser fill default type parity (openclaw#27662) (thanks @Uface11) * test(gateway): align outbound session assertion shape * docs(changelog): credit reporter for pairing isolation fix * refactor(browser): unify fill field normalization * fix: forward resolved session key in agent delivery (follow-up openclaw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local> * refactor(nodes): share default selection and tighten node.list fallback * test: fix pairing/daemon assertion drift * test: fix TS2783 in nodes-utils helper * docs: reorder unreleased 2026.2.26 changelog entries * fix(cli): accept node24 executable names in argv reparse * fix: preserve assistant usage snapshots during compaction cleanup * refactor(channels): unify dm pairing policy flows * fix(models): extend gpt-5.3-codex forward compat to github-copilot The codex forward-compat fallback only matched openai-codex, leaving github-copilot users without gpt-5.3-codex despite the model being available on the Copilot API. Made-with: Cursor * fix(delivery-queue): change break to continue to prevent head-of-line blocking When an entry's backoff exceeds the recovery budget, the code was using break which blocked all subsequent entries from being processed. This caused permanent queue blockage for any installation with a delivery entry at retryCount >= 2. Fix: Changed break to continue so entries whose backoff exceeds the remaining budget are skipped individually rather than blocking the entire loop. Closes openclaw#27638 * fix: harden delivery recovery backoff eligibility and tests (openclaw#27710) (thanks @Jimmy-xuzimo) * docs(security): clarify parity-only command-risk reports * refactor(daemon): unify runtime binary detection * refactor(outbound): split recovery counters and normalize legacy retry entries * chore: silence onboard warning noise * fix(googlechat): keep startAccount pending until abort to prevent restart loop * fix: add googlechat lifecycle regression test (openclaw#27384) (thanks @junsuwhy) * fix: harden temp dir perms for umask 0002 (landed from openclaw#27860 by @stakeswky) Co-authored-by: 不做了睡大觉 <stakeswky@gmail.com> * fix(nextcloud-talk): keep startAccount pending until abort (openclaw#27897) * test: align compaction hook usage expectation * fix(cli): make gateway --force resilient to lsof EACCES * test: align compaction hook usage expectation * fix: reject dmPolicy="allowlist" with empty allowFrom across all channels When dmPolicy is set to "allowlist" but allowFrom is missing or empty, all DMs are silently dropped because no sender can match the empty allowlist. This is a common pitfall after upgrades that change how allowlist files are handled (e.g., external allowlist-dm.json files being deprecated in favor of inline allowFrom arrays). Changes: - Add requireAllowlistAllowFrom schema refinement (zod-schema.core.ts) - Apply validation to all channel schemas: Telegram, Discord, Slack, Signal, IRC, iMessage, BlueBubbles, MS Teams, Google Chat, WhatsApp - Add detectEmptyAllowlistPolicy to doctor-config-flow.ts so "openclaw doctor" surfaces a clear warning with remediation steps - Add 12 test cases covering reject/accept for multiple channels Fixes openclaw#27892 * fix: skip allowFrom validation at account level (inherits from parent) Account configs inherit channel-level fields at runtime (e.g., resolveTelegramAccount shallow-merges top-level and account values). An account can set dmPolicy='allowlist' and rely on the parent's allowFrom, so validating allowFrom on the account object alone incorrectly rejects valid multi-account configs. Removes requireAllowlistAllowFrom and requireOpenAllowFrom from all account-level schemas (Telegram, Signal, IRC, iMessage, BlueBubbles). Top-level config schemas still enforce the validation. Addresses Codex review feedback on openclaw#27936. * fix: enforce dm allowFrom inheritance across account channels (openclaw#27936) (thanks @widingmarcus-cyber) * Protocol: regenerate Swift models for systemRunPlanV2 * docs(changelog): reorder docker gateway fix by user impact * chore(release): cut 2026.2.26-beta.1 * chore(release): point appcast to beta tag * fix(ios): eliminate Swift warnings and clean build logs * fix: unblock CI minimatch audit and host policy check * fix(ci): align sync boundary realpath canonicalization * Changelog: include Gemini OAuth PRs openclaw#16683 and openclaw#16684 (openclaw#27987) * fix: repair Telegram allowlist DM migrations (openclaw#27936) (thanks @widingmarcus-cyber) * docs(cli): improve secrets command guide * Docs: expand ACP first-use naming and link protocol site * fix(agents): add forward-compat fallback for google-gemini-cli gemini-3.1-pro/flash-preview (openclaw#26570) * fix(agents): add "google" provider to isReasoningTagProvider to prevent reasoning leak The gemini-api-key auth flow creates a profile with provider "google" (e.g. google/gemini-3-pro-preview), but isReasoningTagProvider only matched "google-gemini-cli" (OAuth) and "google-generative-ai". As a result: - reasoningTagHint was false → system prompt omitted <think>/<final> formatting instructions - enforceFinalTag was false → <final> tag filtering was skipped Raw <think> reasoning output was delivered to the end user. Fix: add the bare "google" provider string to the match list and cover it with two new test cases (exact match + case-insensitive). Fixes openclaw#26551 * fix(agents): add forward-compat fallback for google-gemini-cli gemini-3.1-pro/flash-preview gemini-3.1-pro-preview and gemini-3.1-flash-preview are not yet present in pi-ai's built-in google-gemini-cli model catalog (only gemini-3-pro-preview and gemini-3-flash-preview are registered). When users configure these models they get "Unknown model" errors even though Gemini CLI OAuth supports them. The codebase already has isGemini31Model() in extra-params.ts, which proves intent to support these models. Add a resolveGoogleGeminiCli31ForwardCompatModel entry to resolveForwardCompatModel following the same clone-template pattern used for zai/glm-5 and anthropic 4.6 models. - gemini-3.1-pro-* clones gemini-3-pro-preview (with reasoning: true) - gemini-3.1-flash-* clones gemini-3-flash-preview (with reasoning: true) Also add test helpers and three test cases to model.forward-compat.test.ts. Fixes openclaw#26524 * Changelog: credit Google Gemini provider fallback fixes --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org> * fix(provider): normalize bare gemini-3 Pro model IDs for google-antigravity (openclaw#24145) * fix(provider): normalize bare gemini-3 Pro model IDs for google-antigravity The Antigravity Cloud Code Assist API requires a thinking-tier suffix (-low or -high) for all Gemini 3 Pro variants. When a user configures a bare model ID like `gemini-3.1-pro`, the API returns a 404 because it only recognises `gemini-3.1-pro-low` or `gemini-3.1-pro-high`. Add `normalizeAntigravityModelId()` that appends `-low` (the default tier) to bare Pro model IDs, and apply it during provider normalisation for `google-antigravity`. Also refactor the per-provider model normalisation into a shared `normalizeProviderModels()` helper. Closes openclaw#24071 Co-authored-by: Cursor <cursoragent@cursor.com> * Tests: cover antigravity model ID normalization * Changelog: note antigravity pro tier normalization * Tests: type antigravity model helper inputs --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Vincent Koc <vincentkoc@ieee.org> * chore(release): cut 2026.2.26 * test: stabilize docker live model suites * ui: remove Google Fonts import blocked by CSP (style-src 'self' 'unsafe-inline'); fonts never loaded; closes openclaw#28038 * docs(telegram): clarify group auth boundary * docs: consolidate grammy links to telegram * docs: remove legacy grammy page * docs(telegram): align channel docs with runtime behavior * fix(update): fallback to --omit=optional when global npm update fails (openclaw#24896) * fix(update): fallback to --omit=optional when global npm update fails * fix(update): add recovery hints and fallback for npm global update failures * chore(update): align fallback progress step index ordering * chore(update): label omit-optional retry step in progress output * chore(update): avoid showing 1/2 when fallback path is not used * chore(ci): retrigger after unrelated test OOM * fix(update): scope recovery hints to npm failures * test(update): cover non-npm hint suppression --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org> * Fix NODE_EXTRA_CA_CERTS missing from LaunchAgent environment on macOS launchd services do not inherit the shell environment, so Node's undici/fetch cannot locate the macOS system CA bundle (/etc/ssl/cert.pem). This causes TLS verification failures for all HTTPS requests (e.g. Telegram, webhooks) when the gateway runs as a LaunchAgent, while the same gateway works fine in a terminal. Add NODE_EXTRA_CA_CERTS defaulting to /etc/ssl/cert.pem on macOS in both buildServiceEnvironment and buildNodeServiceEnvironment. User-supplied NODE_EXTRA_CA_CERTS is always respected and takes precedence. Fixes openclaw#22856 Co-authored-by: Clawborn <tianrun.yang103@gmail.com> * fix: add missing closing brace in proxy env test * fix: stabilize launchd CA env tests (openclaw#27915) (thanks @Lukavyi) * Fix npm-spec plugin installs when npm pack output is empty (openclaw#21039) * fix(plugins): recover npm pack archive when stdout is empty * test(plugins): create npm pack archive in metadata mock --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org> * fix(plugins): clear error when npm package not found (Closes openclaw#24993) (openclaw#25073) * Docs: align gateway config key paths with metadata (openclaw#28196) * Docs: align gateway config key paths in reference * Docs: expand config reference coverage for channels plugins and providers * fix(android): parse camera and screen invoke params as JSON * test(android): cover camera clip upload URL JSON parsing * refactor(android): make camera clip transport deterministic * test(android): cover camera clip payload size guard * fix(android): reject non-positive camera maxWidth * fix: update changelog for android camera clip (openclaw#28229) (thanks @obviyus) * Changelog: add missing npm update and plugin fix credits (openclaw#28257) * feat(android): add camera list and device selection * feat(nodes): add device status and info actions * docs(nodes): document android camera list and device actions * fix(android): scale invoke result ack timeout to invoke budget * feat(node): add device diagnostics and notification action commands * feat(android): implement device diagnostics and notification actions * feat(nodes): expose device diagnostics and notification actions * fix(nodes): reject facing=both when camera deviceId is set * fix(android): allow open and reply on non-clearable notifications * fix(android): rebind listener before notification actions * refactor(nodes): map read actions to invoke commands * refactor(android-node): unify notifications snapshot rebind preflight * refactor(android-node): share battery snapshot parsing across device handlers * docs(changelog): note android node diagnostics and action updates (openclaw#28260) (thanks @obviyus) * fix: add npm link to fix CLI permission denied (exit 127) (openclaw#17151) Co-authored-by: Yutaka Sasaki <sskyu@minio.local> * CI: smoke test root Dockerfile openclaw CLI (openclaw#28308) * Docker: replace npm link with root CLI symlink (openclaw#28312) * Gateway: improve device-auth v2 migration diagnostics (openclaw#28305) * Gateway: add device-auth detail code resolver * Gateway: emit specific device-auth detail codes * Gateway tests: cover nonce and signature detail codes * Docs: add gateway device-auth migration diagnostics * Docs: add device-auth v2 troubleshooting signatures * fix(agents): demote Ollama empty-discovery log from warn to debug (openclaw#26379) When Ollama responds successfully but returns zero models (e.g. on Linux with the bundled `ollama-stub.service`), `discoverOllamaModels` was logging at `warn` level: [agents/model-providers] No Ollama models found on local instance This appeared on every agent invocation even when Ollama was not intentionally configured, polluting production logs. An empty model list is a normal operational state — it warrants at most a debug note, not a warning. Fix: change `log.warn` → `log.debug` for the zero-models branch. The error paths (HTTP failure, fetch exception) remain at `warn` since those indicate genuine connectivity problems. Closes openclaw#26354 * test: add android integration test script * docs: document android capability sweep in testing guide * feat(android): wire runtime canvas capability refresh * feat(gateway): add node canvas capability refresh flow * test(gateway): add live android capability integration suite * docs(android): add integration test preconditions and pitfalls * fix(android): retry A2UI after canvas capability refresh * fix(android): return valid debug.ed25519 diagnostics JSON * fix(media): serve JavaScript assets with text/javascript * fix(android): refresh scoped canvas URLs without trailing slash * fix(android): avoid duplicate A2UI readiness probe on happy path * fix: update changelog for android capability refresh land (openclaw#28388) (thanks @obviyus) * fix(android): send object params for canvas capability refresh * fix: document canvas capability refresh params fix (openclaw#28413) (thanks @obviyus) * Discord: thread bindings idle + max-age lifecycle (openclaw#27845) (thanks @osolmaz) * refactor discord thread bindings to idle and max-age lifecycle * fix: migrate legacy thread binding expiry and reduce hot-path disk writes * refactor: remove remaining thread-binding ttl legacy paths * fix: harden thread-binding lifecycle persistence * Discord: fix thread binding types in message/reply paths * Infra: handle win32 unknown inode in file identity checks * Infra: relax win32 guarded-open identity checks * Config: migrate threadBindings ttlHours to idleHours * Revert "Infra: relax win32 guarded-open identity checks" This reverts commit de94126. * Revert "Infra: handle win32 unknown inode in file identity checks" This reverts commit 96fc5dd. * Discord: re-read live binding state before sweep unbind * fix: add changelog note for thread binding lifecycle update (openclaw#27845) (thanks @osolmaz) --------- Co-authored-by: Onur Solmaz <onur@textcortex.com> * fix(telegram): include replied media files in reply context (openclaw#28488) * fix(telegram): include replied media files in reply context * fix(telegram): keep reply media fields nullable * perf(telegram): defer reply-media fetch to debounce flush * fix(telegram): gate and preserve reply media attachments * fix(telegram): preserve cached-sticker reply media context * fix: update changelog for telegram reply-media context fixes (openclaw#28488) (thanks @obviyus) * fix(agents): normalize whitespace-padded tool call names before dispatch (openclaw#27094) Fix tool-call lookup failures when models emit whitespace-padded names by normalizing both transcript history and live streamed embedded-runner tool calls before dispatch. Co-authored-by: wangchunyue <80630709+openperf@users.noreply.github.com> Co-authored-by: Sid <sidqin0410@gmail.com> Co-authored-by: Philipp Spiess <hello@philippspiess.com> * feat(i18n): add German (de) locale (openclaw#28495) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: e418326 Co-authored-by: dsantoreis <220753637+dsantoreis@users.noreply.github.com> Co-authored-by: Evizero <10854026+Evizero@users.noreply.github.com> Reviewed-by: @Evizero * chore: add collaboration rules and OpenRouter env passthrough * docs: add krakra final mapping and production config template --------- Signed-off-by: joshavant <830519+joshavant@users.noreply.github.com> Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com> Co-authored-by: Peter Steinberger <steipete@gmail.com> Co-authored-by: taw0002 <webmaster@sodsolutions.com> Co-authored-by: SidQin-cyber <sidqin0410@gmail.com> Co-authored-by: Kevin Shenghui <shenghuikevin@github.com> Co-authored-by: Ayaan Zaidi <hi@obviy.us> Co-authored-by: damaozi <1811866786@qq.com> Co-authored-by: AI Assistant <ai@assistant.local> Co-authored-by: riccoyuanft <riccoyuan@gmail.com> Co-authored-by: Ayaan Zaidi <zaidi@uplause.io> Co-authored-by: Shakker <shakkerdroid@gmail.com> Co-authored-by: jaden-clovervnd <91520439+jaden-clovervnd@users.noreply.github.com> Co-authored-by: Sid <201593046+Sid-Qin@users.noreply.github.com> Co-authored-by: Marcus Widing <245375637+widingmarcus-cyber@users.noreply.github.com> Co-authored-by: Liu Yuan <namei.unix@gmail.com> Co-authored-by: Rafal <mrsikorarafal@gmail.com> Co-authored-by: Viz <visionik@pobox.com> Co-authored-by: Nimrod Gutman <nimrod.g@singular.net> Co-authored-by: AytuncYildizli <cryptosquanch@gmail.com> Co-authored-by: Shadow <hi@shadowing.dev> Co-authored-by: Vincent Koc <vincentkoc@ieee.org> Co-authored-by: Taras Shynkarenko <taras.shinkarenko@gmail.com> Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local> Co-authored-by: ACV <acv@Mac.home> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Rick <agentrick@Mac.localdomain> Co-authored-by: Xu Zimo <xuzimojimmy@163.com> Co-authored-by: Chang Shu-Huai <junsuwhy@gmail.com> Co-authored-by: 不做了睡大觉 <stakeswky@gmail.com> Co-authored-by: Marcus Widing <widing.marcus@gmail.com> Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Byungsker <72309817+byungsker@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Xinhua Gu <xinhua.gu@gmail.com> Co-authored-by: Clawborn <tianrun.yang@hotmail.com> Co-authored-by: Clawborn <tianrun.yang103@gmail.com> Co-authored-by: clawdbot <lukavyi@me.com> Co-authored-by: graysurf <10785178+graysurf@users.noreply.github.com> Co-authored-by: Dale Yarborough <daleyarborough@gmail.com> Co-authored-by: Yutaka Sasaki <sskyutaka@gmail.com> Co-authored-by: Yutaka Sasaki <sskyu@minio.local> Co-authored-by: Onur Solmaz <2453968+osolmaz@users.noreply.github.com> Co-authored-by: Onur Solmaz <onur@textcortex.com> Co-authored-by: wangchunyue <80630709+openperf@users.noreply.github.com> Co-authored-by: Daniel Reis <dsantoreis@gmail.com> Co-authored-by: dsantoreis <220753637+dsantoreis@users.noreply.github.com> Co-authored-by: Evizero <10854026+Evizero@users.noreply.github.com> Co-authored-by: KrD-Hub <93096409+KrD-Hub@users.noreply.github.com> Co-authored-by: KraKra <krakra@KraKras-MacBook-Pro.local>
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 27, 2026
…7584) (thanks @qualiobra) (cherry picked from commit 24b399b)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 27, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local> (cherry picked from commit e733b89)
execute008
pushed a commit
to execute008/openclaw
that referenced
this pull request
Feb 27, 2026
r4jiv007
pushed a commit
to r4jiv007/openclaw
that referenced
this pull request
Feb 28, 2026
r4jiv007
pushed a commit
to r4jiv007/openclaw
that referenced
this pull request
Feb 28, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local>
mylukin
pushed a commit
to mylukin/openclaw
that referenced
this pull request
Feb 28, 2026
mylukin
pushed a commit
to mylukin/openclaw
that referenced
this pull request
Feb 28, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local>
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 28, 2026
…7584) (thanks @qualiobra) (cherry picked from commit 24b399b)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 28, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local> (cherry picked from commit e733b89)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 28, 2026
…7584) (thanks @qualiobra) (cherry picked from commit 24b399b)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 28, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local> (cherry picked from commit e733b89)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 28, 2026
…7584) (thanks @qualiobra) (cherry picked from commit 24b399b)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 28, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local> (cherry picked from commit e733b89)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 28, 2026
…7584) (thanks @qualiobra) (cherry picked from commit 24b399b)
wanjizheng
pushed a commit
to wanjizheng/openclaw
that referenced
this pull request
Feb 28, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local> (cherry picked from commit e733b89)
vincentkoc
pushed a commit
to Sid-Qin/openclaw
that referenced
this pull request
Feb 28, 2026
vincentkoc
pushed a commit
to Sid-Qin/openclaw
that referenced
this pull request
Feb 28, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local>
vincentkoc
pushed a commit
to rylena/rylen-openclaw
that referenced
this pull request
Feb 28, 2026
vincentkoc
pushed a commit
to rylena/rylen-openclaw
that referenced
this pull request
Feb 28, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local>
6 tasks
hughdidit
pushed a commit
to hughdidit/DAISy-Agency
that referenced
this pull request
Mar 1, 2026
…7584) (thanks @qualiobra) (cherry picked from commit 4cb4053) # Conflicts: # CHANGELOG.md
hughdidit
pushed a commit
to hughdidit/DAISy-Agency
that referenced
this pull request
Mar 1, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local> (cherry picked from commit 7ef6623) # Conflicts: # CHANGELOG.md # src/commands/agent/delivery.ts
steipete
added a commit
to Sid-Qin/openclaw
that referenced
this pull request
Mar 2, 2026
steipete
added a commit
to Sid-Qin/openclaw
that referenced
this pull request
Mar 2, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local>
safzanpirani
pushed a commit
to safzanpirani/clawdbot
that referenced
this pull request
Mar 2, 2026
safzanpirani
pushed a commit
to safzanpirani/clawdbot
that referenced
this pull request
Mar 2, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local>
robertchang-ga
pushed a commit
to robertchang-ga/openclaw
that referenced
this pull request
Mar 2, 2026
hughdidit
pushed a commit
to hughdidit/DAISy-Agency
that referenced
this pull request
Mar 3, 2026
…7584) (thanks @qualiobra) (cherry picked from commit 4cb4053) # Conflicts: # CHANGELOG.md
hughdidit
pushed a commit
to hughdidit/DAISy-Agency
that referenced
this pull request
Mar 3, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local> (cherry picked from commit 7ef6623) # Conflicts: # CHANGELOG.md # src/commands/agent/delivery.ts
dorgonman
pushed a commit
to kanohorizonia/openclaw
that referenced
this pull request
Mar 3, 2026
dorgonman
pushed a commit
to kanohorizonia/openclaw
that referenced
this pull request
Mar 3, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local>
zooqueen
pushed a commit
to hanzoai/bot
that referenced
this pull request
Mar 6, 2026
zooqueen
pushed a commit
to hanzoai/bot
that referenced
this pull request
Mar 6, 2026
…aw#27584 by @qualiobra) Co-authored-by: Lucas Teixeira Campos Araujo <lucas@MacBook-Pro-de-Lucas.local>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The
message:sentinternal hook event never fires because most call sites ofdeliverOutboundPayloads()don't pass thesessionKeyparameter. Indeliver.ts, the guard:...silently skips the
triggerInternalHook()call, so hooks registered formessage:sentnever receive events.Root Cause
The
sessionKeyparameter was added toDeliverOutboundPayloadsCoreParamsbut was only being passed fromroute-reply.ts(viamirror). The other 5 call sites never passed it.Fix
Pass
sessionKeyfrom all call sites where it's available:commands/agent/delivery.tsopts.sessionKeyinfra/heartbeat-runner.ts(×2)sessionKey(from preflight)infra/outbound/message.tsparams.mirror?.sessionKeycron/isolated-agent/delivery-dispatch.tsparams.agentSessionKeygateway/server-node-events.tsparams.sessionKeyImpact
message:sentwill now fire correctlymessage_sentplugin hooks are unaffected (they use a separate code path viahookRunner.runMessageSent)message:senthooksTesting
Verified with a custom hook that logs to Supabase — before this fix, only
message:receivedevents were captured. After, both directions work.