Gateways that crash-loop under systemd/launchd previously flapped forever
with no persisted state and no supervisor signal. The gateway now records
every boot outcome in the shared state DB (gateway_boot_lifecycle); three
unclean boots within five minutes trip a breaker that boots the gateway in
safe mode: full control plane available, channel/provider auto-start
suppressed at the channel-manager seam (startup, config hot-reload,
secrets.reload) with manual channels.start override, one stability bundle
per trip. The breaker re-evaluates each boot and logs recovery when the
window drains. Slow shutdowns record forced_stop and never count as
crashes; /readyz stays ready and reports suppressed channels; the health
monitor treats suppressed accounts as expected-stopped. Fatal invalid-config
errors now exit 78 (EX_CONFIG) on both the startup and unhandled-rejection
paths, engaging the systemd unit's pre-existing RestartPreventExitStatus=78
so supervisors stop relaunching until the config is fixed.
Summary:
- Merged feat(tencent): add Tencent Hy3 provider (TokenHub and TokenPlan) after ClawSweeper review.
Automerge notes:
- Ran the ClawSweeper repair loop before final review.
- Included post-review commit in the final squash: fix(tencent): preserve TokenHub auth compatibility
- Included post-review commit in the final squash: refactor(tencent): unify TokenPlan env/flag naming with TokenHub
- Included post-review commit in the final squash: docs: refresh Tencent provider docs metadata
- Included post-review commit in the final squash: fix: allow TokenPlan provider config overlays
- Included post-review commit in the final squash: docs: dedupe Tencent provider glossary labels
- Included post-review commit in the final squash: fix(tencent): repair TokenHub model defaults
Validation:
- ClawSweeper review passed for head 30c9fc130f.
- Required merge gates passed before the squash merge.
Prepared head SHA: 30c9fc130f
Review: https://github.com/openclaw/openclaw/pull/99076#issuecomment-4888527271
Co-authored-by: leisang <leisang@tencent.com>
Co-authored-by: Mason Huang <masonxhuang@tencent.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: hxy91819
Opt-in per-account (agentActivity: true): the ClickClack channel extension
now mirrors streamed commentary and tool progress into durable
agent_commentary / agent_tool message rows via the existing
replyOptions.onItemEvent seam, coalesced so one logical step is one row.
Requires a bot token carrying the agent_activity:write scope; publishing
is best-effort and never interrupts final text delivery.
* feat(control-ui): session grouping with drag & drop and channel categorization
* fix(control-ui): restrict session drag&drop to private session-key payloads
* chore(i18n): translate session grouping strings across control ui locales
* chore(protocol): regenerate swift gateway models for session category
* chore(protocol): regenerate swift gateway models for session category
* feat(slack): add ignoreOtherMentions channel config
Mirrors the existing Discord `ignoreOtherMentions` option for Slack
channels. When set on a channel entry, drop channel/group/MPIM messages
that mention another user or subteam but not this bot — the inverse of
`requireMention`. Useful in busy channels where the bot would otherwise
reply to side conversations.
Implementation lives in `prepareSlackMessage` right after the
`allowBots: "mentions"` bot-drop gate and before the `shouldRequireMention`
non-mention drop, so it integrates with the new `messageIngress` ingress
pipeline. The gate is conditional on `canDetectMention` (botUserId
resolvable via `auth.test` or explicit mention regexes configured) to
avoid false drops when we have no reliable way to tell bot vs non-bot
mentions apart.
Slack implicit mentions (thread participation) are intentionally NOT
respected here — they fire for every message in a bot-participated
thread, so honoring them would defeat the feature in any active thread.
The gate matches on `wasMentioned` (explicit) and `hasAnyMention`, with
the existing `shouldBypassMention` override (e.g. authorized commands)
also respected.
Includes config types, zod schema, channel-config resolution,
prepare-message implementation, full test coverage in
`prepare.test.ts`, regenerated channel + docs baselines, and Slack
docs entry.
* refactor(slack): harden other-mention filtering
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(telegram): resolve local Bot API container file paths against trustedLocalFileRoots
When the self-hosted telegram-bot-api server runs with --local inside a
container, getFile returns absolute file_path values rooted at the
container data dir (/var/lib/telegram-bot-api/...). The host process
mounts that volume at a different path, so the absolute path never
matches a trustedLocalFileRoots entry and inbound media fails to
materialize (messages reach the agent as bare <media:document>
placeholders without bytes).
Map container-absolute paths back to relative candidates and resolve
them under each trusted root, trying both with and without the
per-token directory segment the local server uses. Relative file_path
values are now also resolved against trusted roots before falling back
to the HTTP file endpoint, which keeps large-file (>20MB) local-mode
downloads working.
Path traversal protections: candidates are normalized, NUL bytes and
dot-segments are rejected, and reads stay behind the trusted-roots
file-access sandbox.
AI-assisted (Claude Code), validated with targeted vitest run.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Dizesales <269209351+Dizesales@users.noreply.github.com>
* fix(telegram): map local Bot API container media paths
Co-authored-by: Lucas Magalhaes <ellucasrj@gmail.com>
* chore(config): refresh channel metadata
---------
Co-authored-by: Lucas Magalhaes <ellucasrj@gmail.com>
Co-authored-by: Dizesales <269209351+Dizesales@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat: add session thread management
Squash of codex/thread-management (025aefc3ad1) onto origin/main:
pin/archive/rename sessions via sessions.patch, archived-aware
sessions.list, lifecycle fencing, read-only archived chat, SDK +
Swift protocol support, Control UI session management.
* refactor(ui): minimal session rows with hover-revealed management
Chat picker and sidebar recents share session-row primitives: single-line
rows, relative timestamps, rename/archive/pin revealed on hover or focus,
accent pin badge for pinned rows, and an active-run spinner in the trail
slot. Sidebar floats pinned sessions above recency via the shared
comparator and gains archive/pin actions through the unified sessions-view
patch fallback. Archive eligibility is one shared policy
(canArchiveSessionRow); the sidebar/picker active-run tooltip now uses the
real sessionsView.activeRun locale key.
* fix: align session admission with mailbox-era main
Integration fixes after rebasing onto current main: sessions_list mailbox
test expectations learn the archived/pinned row fields and archived:false
list param; gateway agent admission treats a session as deleted only when
both the requested and canonical alias sets miss it (legacy bare-main
stores and exec-approval followups read under different spellings); cron
persist tests keep a consistent store across claim-guarded persist calls;
the ACP abort hook test asserts abort propagation instead of signal
identity; drop dead lifecycle writes flagged by no-useless-assignment and
fix the promise-executor return in the codex compact test.
* fix(qa): align UI e2e and shard fixtures with redesigned session rows
Sidebar session rows are wrapper divs with an inner link now: update the
navigation browser tests and chat-flow Playwright selectors. Seed a real
per-test session store for the auto-fallback admission guard instead of
depending on leftover host files at /tmp/sessions.json. Teach the
test-projects routing fixture about the suites that newly import the
shared temp-dir helper. Document the Codex thread-format contract for
archivedAt/pinnedAt (flag derived from server-stamped timestamp, epoch ms
here vs Codex epoch seconds) at the type and in the session docs.
* test: route auto-fallback suite through temp-dir helper plans
The auto-fallback suite now imports the shared temp-dir helper for its
seeded session store, so the top-level helper routing fixture must list
it in the auto-reply plan.
* fix(transcripts): mark delivery mirrors as artifacts
* fix(transcripts): mark delivery mirrors as artifacts
* fix(transcripts): mark delivery mirrors as artifacts
* feat(signal): add target aliases
* fix(signal): canonicalize alias delivery targets
* fix(signal): harden alias target resolution
* test(signal): cover formatted media aliases
* test(signal): align approval alias proof with request shape
* Reuse Signal alias map for directory listing
* fix(config): use Object.hasOwn instead of in operator in restoreOriginalValueOrThrow
* test(config): add regression test for prototype-named keys in restoreRedactedValues
* test(config): focus prototype restore regression
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Ambient transcript watermarks now carry the transcript session id, resolve only for the current session entry, and skip stale room-event hooks that no longer match the prepared transcript session.
This protects Telegram group prompt windows after reset by backfilling rows that are no longer present in the new session transcript, while preserving steady-state watermark filtering within one session.
Fixes#99373
Release-note: fixes Telegram group context loss after session reset when ambient transcript watermarks outlived the transcript they referenced.
Persist room-event observations as durable bare user transcript rows and carry an ambient transcript watermark through session state so Telegram chat windows only include the unpersisted gap.
Fixes#99257
* fix(config/sessions): narrow reply-session initialization revision to identity fields
The initialization guard compared the full persisted session entry, so
background touches to updatedAt, heartbeat timestamps, context-budget
metadata, etc. produced false-positive stale-snapshot conflicts and the
"reply session initialization conflicted" error.
Only sessionId and sessionFile matter for detecting a session rotation.
Narrow the revision to those identity fields and add a regression test.
Fixes#98672
* fix(config/sessions): merge current metadata when reply-init identity guard passes
* fix(config/sessions): preserve only snapshot-drifted metadata in reply-init commit
* fix: preserve cleared reply-session metadata
* fix: allow same-session reply initialization drift
---------
Co-authored-by: moguangyu5-design <moguangyu5-design@users.noreply.github.com>
Co-authored-by: Josh Lehman <josh@martian.engineering>