Skip to content

fix(telegram): include replied media files in reply context#28488

Merged
obviyus merged 6 commits intomainfrom
fix/telegram-reply-media-context
Feb 27, 2026
Merged

fix(telegram): include replied media files in reply context#28488
obviyus merged 6 commits intomainfrom
fix/telegram-reply-media-context

Conversation

@obviyus
Copy link
Contributor

@obviyus obviyus commented Feb 27, 2026

Summary

When a user replies to a Telegram image with text, inbound context only included reply metadata (ReplyToBody: <media:image>) and not the actual replied media file.

This patch adds replied-media resolution and merges replied media paths/types into context media fields so vision-capable models can inspect the image again.

What changed

  • resolve replied message media in Telegram inbound handler
  • pass replyMedia through message processor/context builder
  • merge replied media into MediaPath(s)/MediaType(s) in final inbound context
  • add regression test for text reply to image

Validation

  • pnpm test src/telegram/bot.test.ts src/telegram/bot-message.test.ts
  • pnpm test src/telegram/bot.create-telegram-bot.test.ts

@openclaw-barnacle openclaw-barnacle bot added channel: telegram Channel integration: telegram size: S maintainer Maintainer-authored PR labels Feb 27, 2026
@obviyus obviyus self-assigned this Feb 27, 2026
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c3091175d2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 27, 2026

Greptile Summary

Resolved replied-media from Telegram messages and merged into inbound context for vision-capable models. The implementation correctly:

  • Added resolveReplyMediaForMessage() to fetch media from replied messages using the Telegram API
  • Passed replyMedia through the message processor and context builder
  • Merged replied media with current message media in MediaPath(s)/MediaType(s) fields
  • Integrated with existing debouncing and media group handling
  • Added regression test coverage for text replies to images

The changes are well-scoped and maintain consistency with existing error handling patterns (graceful degradation on fetch failures).

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The implementation is correct and well-integrated into existing code patterns. Type safety is maintained throughout, error handling follows established patterns with graceful degradation, and test coverage validates the core functionality. No logical errors or security issues were found.
  • No files require special attention

Last reviewed commit: 8833dbe

@obviyus
Copy link
Contributor Author

obviyus commented Feb 27, 2026

Addressed follow-up perf concern (reply-media + debounce):

  • moved resolveReplyMediaForMessage from pre-enqueue path to debounce flush path
  • single message: resolve once at flush
  • merged debounced messages: resolve once from synthetic message context
  • removed per-fragment eager reply-media fetch, so repeated quick replies no longer trigger duplicate getFile/download work
  • added regression test: defers reply media download until debounce flush

Validation:

  • pnpm test src/telegram/bot.test.ts
  • pnpm test src/telegram/bot.create-telegram-bot.test.ts src/telegram/bot-message.test.ts
  • pnpm check

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 95cb02bf28

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@obviyus
Copy link
Contributor Author

obviyus commented Feb 27, 2026

Addressed both additional P2 findings:

  1. DM auth gate for reply-media fetch
  • Added hasReplyTargetMedia and extended early DM auth gate in bot-handlers.
  • Unauthorized DM replies to media now exit before any reply-media getFile/download.
  1. Preserve reply media on sticker fallback
  • Replaced blanket Media* clearing with pruneStickerMediaFromContext in bot-message-dispatch.
  • Non-vision sticker fallback now removes only the primary sticker slot and keeps appended reply media.

Tests added:

  • does not fetch reply media for unauthorized DM replies (src/telegram/bot.test.ts)
  • src/telegram/bot-message-dispatch.sticker-media.test.ts

Validation:

  • pnpm test src/telegram/bot.test.ts src/telegram/bot-message-dispatch.sticker-media.test.ts
  • pnpm check

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aa6773338b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@obviyus
Copy link
Contributor Author

obviyus commented Feb 27, 2026

Addressed cached-sticker pruning edge case:

  • Added StickerMediaIncluded context flag in bot-message-context.
    • true when current sticker media is actually present in MediaPaths
    • false for cached-sticker path where sticker media is omitted and only reply media may remain
  • Updated pruneStickerMediaFromContext to no-op when stickerMediaIncluded === false.
  • Dispatch now passes that flag into prune, so cached-sticker replies retain replied media.

Added regression:

  • src/telegram/bot-message-dispatch.sticker-media.test.ts
    • no-prune path when sticker media already omitted

Validation:

  • pnpm test src/telegram/bot-message-dispatch.sticker-media.test.ts src/telegram/bot.test.ts
  • pnpm check

@obviyus obviyus force-pushed the fix/telegram-reply-media-context branch from a2350b6 to 7447bc4 Compare February 27, 2026 09:46
@obviyus obviyus merged commit aae90cb into main Feb 27, 2026
6 checks passed
@obviyus obviyus deleted the fix/telegram-reply-media-context branch February 27, 2026 09:46
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7447bc490a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

});
const messageIdOverride = last.msg.message_id ? String(last.msg.message_id) : undefined;
const syntheticCtx = buildSyntheticContext(baseCtx, syntheticMessage);
const replyMedia = await resolveReplyMediaForMessage(baseCtx, syntheticMessage);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve debounced reply media from latest fragment

In the multi-entry debounce path, reply media is resolved from syntheticMessage (which is cloned from first.msg) even though the merged response is anchored to the last fragment (messageIdOverride from last.msg.message_id). When debounce is enabled and a user sends quick consecutive texts where only a later fragment carries the reply (or carries a different reply target), the model gets missing/incorrect reply media for the message it is actually responding to.

Useful? React with 👍 / 👎.

mrosmarin added a commit to mrosmarin/openclaw that referenced this pull request Feb 27, 2026
* main:
  fix(telegram): include replied media files in reply context (openclaw#28488)
github-actions bot pushed a commit to tankerwng2/openclaw that referenced this pull request Feb 27, 2026
…#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)
sunquangang pushed a commit to ottin4ttc/openclaw that referenced this pull request Feb 27, 2026
…#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)
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
…#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)
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Feb 27, 2026
…#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)

(cherry picked from commit e5bc981)
execute008 pushed a commit to execute008/openclaw that referenced this pull request Feb 27, 2026
…#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)
r4jiv007 pushed a commit to r4jiv007/openclaw that referenced this pull request Feb 28, 2026
…#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)
mylukin pushed a commit to mylukin/openclaw that referenced this pull request Feb 28, 2026
…#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)
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Feb 28, 2026
…#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)

(cherry picked from commit e5bc981)
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Feb 28, 2026
…#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)

(cherry picked from commit e5bc981)
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Feb 28, 2026
…#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)

(cherry picked from commit e5bc981)
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Feb 28, 2026
…#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)

(cherry picked from commit e5bc981)
alanz added a commit to alanz/openclaw that referenced this pull request Feb 28, 2026
Adds a full Delta.Chat channel extension to OpenClaw, enabling the
assistant to send and receive messages over the Delta.Chat protocol
(email-based end-to-end encrypted messaging via JSON-RPC).

Key capabilities:

- JSON-RPC client via @deltachat/stdio-rpc-server and @deltachat/jsonrpc-client
- Inbound message monitoring using IncomingMsg events with self-echo filter
  and deduplication
- Outbound messaging via miscSendTextMessage() with chatId-based routing
- Liveness reaction cycling (⏳ ⚙️ 🤔 💭) while the agent processes,
  cleared on reply; configurable interval and enable/disable flag
- Ack reaction support with configurable reactionLevel (off/ack/minimal/extensive)
- QR code pairing flow with gateway-managed QR code storage
- Security policies: DMs (disabled/pairing/allowlist/open),
  groups (allowlist/open)
- Per-sender and chatId-based session key derivation for DM routing
- Group configuration: requireMention, tools, toolsBySender policies
- Mention detection so authorized commands bypass requireMention gating
- Media support for inbound and outbound messages; reply/quoted message
  media fetched at debounce-flush time and merged into MediaPaths
  (mirrors Telegram's reply-media handling from openclaw#28488)
- Configurable data directory (default: ~/.openclaw/state/deltachat)
- Connectivity deduplication and RPC-server logger

Extension follows OpenClaw plugin patterns:
- Zod schema validation for all configuration
- Platform-specific npm optional dependencies
- Full channel interface with reactions capability
- Comprehensive test suite (monitor, send, reactions, rpc-server)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
vincentkoc pushed a commit to Sid-Qin/openclaw that referenced this pull request Feb 28, 2026
…#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)
vincentkoc pushed a commit to rylena/rylen-openclaw that referenced this pull request Feb 28, 2026
…#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)
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Mar 1, 2026
…#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)
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Mar 1, 2026
…#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)
steipete pushed a commit to Sid-Qin/openclaw that referenced this pull request Mar 2, 2026
…#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)
safzanpirani pushed a commit to safzanpirani/clawdbot that referenced this pull request Mar 2, 2026
…#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)
venjiang pushed a commit to venjiang/openclaw that referenced this pull request Mar 2, 2026
…#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)
dorgonman pushed a commit to kanohorizonia/openclaw that referenced this pull request Mar 3, 2026
…#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)
alanz added a commit to alanz/openclaw that referenced this pull request Mar 4, 2026
Adds a full Delta.Chat channel extension to OpenClaw, enabling the
assistant to send and receive messages over the Delta.Chat protocol
(email-based end-to-end encrypted messaging via JSON-RPC).

Key capabilities:

- JSON-RPC client via @deltachat/stdio-rpc-server and @deltachat/jsonrpc-client
- Inbound message monitoring using IncomingMsg events with self-echo filter
  and deduplication
- Outbound messaging via miscSendTextMessage() with chatId-based routing
- Liveness reaction cycling (⏳ ⚙️ 🤔 💭) while the agent processes,
  cleared on reply; configurable interval and enable/disable flag
- Ack reaction support with configurable reactionLevel (off/ack/minimal/extensive)
- QR code pairing flow with gateway-managed QR code storage
- Security policies: DMs (disabled/pairing/allowlist/open),
  groups (allowlist/open)
- Per-sender and chatId-based session key derivation for DM routing
- Group configuration: requireMention, tools, toolsBySender policies
- Mention detection so authorized commands bypass requireMention gating
- Media support for inbound and outbound messages; reply/quoted message
  media fetched at debounce-flush time and merged into MediaPaths
  (mirrors Telegram's reply-media handling from openclaw#28488)
- Configurable data directory (default: ~/.openclaw/state/deltachat)
- Connectivity deduplication and RPC-server logger

Extension follows OpenClaw plugin patterns:
- Zod schema validation for all configuration
- Platform-specific npm optional dependencies
- Full channel interface with reactions capability
- Comprehensive test suite (monitor, send, reactions, rpc-server)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
…#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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: telegram Channel integration: telegram maintainer Maintainer-authored PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant