Commit Graph

62204 Commits

Author SHA1 Message Date
wangmiao0668000666 f9fffe241b fix(nostr): clear per-relay publish timeout timer to prevent dangling handles (#98720)
(cherry picked from commit a7a444e7ef)
2026-07-14 01:52:18 -07:00
Leonidas Lux dadc1c3faa fix(whatsapp): restore malformed credentials from backup (#99070)
* fix(whatsapp): wrap JSON.parse with try-catch in auth store and test helpers

Add defensive try-catch around JSON.parse calls in WhatsApp extension
to prevent crashes from corrupted state files.

- restoreCredsFromBackupIfNeeded: wrap creds.json/backup validation
  JSON.parse with try-catch; corrupted creds.json now properly falls
  through to backup restoration instead of skipping it entirely
- updateLastRouteMock: wrap JSON.parse with try-catch, initialize
  empty store on corrupted file

* test(whatsapp): add regression test for malformed creds.json longer than one byte

- Add a focused regression test for the exact case ClawSweeper
  flagged: readWebCredsJsonRawSync returns non-null content for
  files with stat.size > 1, so malformed JSON like "{x" (2 bytes)
  reaches JSON.parse — the inner try-catch now catches the parse
  failure and falls through to backup restoration
- Without this patch, JSON.parse("{x") throws to the outer catch
  and restoreCredsFromBackupIfNeeded returns false, skipping backup

🦞 diamond lobster: L2 evidence (real function call + real filesystem objects)

Ref. https://github.com/openclaw/openclaw/pull/99070

* fix(whatsapp): restore malformed creds from backup

Co-authored-by: LeonidasLux <LeonidasLux@users.noreply.github.com>

* docs(changelog): defer credential recovery entry to aggregate

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: LeonidasLux <LeonidasLux@users.noreply.github.com>
(cherry picked from commit 42464de58d)
2026-07-14 01:52:18 -07:00
Peter Lee 1a621a17b6 fix(whatsapp): thread authDir through command authorization and owner bypass for LID JID resolution (#93379)
* fix(whatsapp): thread authDir through command authorization and owner bypass for LID JID resolution

WhatsApp group commands (/new, /stop) can be ignored when Baileys reports the sender as a LID JID (@lid) instead of a phone JID (@s.whatsapp.net). The resolveWhatsAppCommandAuthorized() and isOwnerSender() functions called getSelfIdentity/getSenderIdentity without passing authDir, so the LID-to-phone reverse mapping could not happen.

Fix: thread account.authDir through both command authorization and group owner-bypass identity resolution paths so that LID JIDs are properly resolved to phone E.164 identities before owner/allowlist checks.

* fix(whatsapp): replace deprecated top-level fields with admission overrides in LID JID test

(cherry picked from commit 85f7834852)
2026-07-14 01:52:18 -07:00
lizeyu f328f7f8b8 fix(update-check): bound npm registry JSON response read to prevent OOM (#98508)
* fix(update-check): bound npm registry JSON response read to prevent OOM

- Replace unbounded res.json() with readProviderJsonResponse capped at 16 MiB
- Update test mock to use real Response instead of bare object
- Verified against live npm registry: openclaw update status --json returns latestVersion: 2026.6.11

* fix(update-check): add 4 boundary tests for bounded npm registry read

- Tests: oversized response >16 MiB, near-boundary success
- Tests: malformed JSON, non-200 status code
- All pass with the readProviderJsonResponse bounded reader

* chore: add real behavior proof script for bounded JSON reader

Adds a standalone proof script that starts a local HTTP server and
drives the bounded reader against it with real HTTP requests, showing:
- Normal responses (~1 MB) parse correctly
- Oversized responses (>20 MB) are rejected with a descriptive error
- Malformed JSON is caught
- RSS does not spike on oversized responses

Ref. https://github.com/openclaw/openclaw/pull/98508

* chore: remove PR-specific proof script before merge

The proof script was accepted by ClawSweeper (proof: sufficient,
rating: diamond lobster), but it duplicates repository logic and
fails the scripts lint lane. Removing it per review feedback.

The real behavior proof remains in the PR body.

Ref. https://github.com/openclaw/openclaw/pull/98508

(cherry picked from commit 733de866eb)
2026-07-14 01:52:18 -07:00
pick-cat b0453d1779 fix(infra): guard delivery queue inflate against corrupted entry_json (#98354)
* fix(infra): guard delivery queue inflate against corrupted entry_json

* fix(infra): use toSorted in delivery queue test

(cherry picked from commit 302524bbd0)
2026-07-14 01:52:17 -07:00
ooiuuii 59f63dd001 fix: redact dotted API key activity previews (#99460)
* fix: redact dotted API key activity previews

* fix(ui): redact quoted activity secrets

* fix(ui): handle quoted secret punctuation

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit e51b446bae)
2026-07-14 01:52:17 -07:00
ooiuuii f19ac6efc9 Redact bare Fireworks API keys (#98226)
* Redact bare Fireworks API keys

* fix(logging): harden Fireworks key redaction

* fix(logging): harden Fireworks key redaction

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit c5bc35de12)
2026-07-14 01:52:17 -07:00
Dallin Romney a98daf0d5c fix(cli): stop pairing list crashing with empty channel enum (#98142)
When no chat DM pairing channels are configured, `openclaw pairing list`
(no channel argument) threw `Channel required ... (expected one of: )`
with an empty enum that reads like a bug. Users who hit this are usually
trying to approve a TUI/device or scope-upgrade request, which lives under
`openclaw devices`, not `openclaw pairing` (which only handles chat DM
pairing).

- Guard the channel hint in help text and errors so an empty channel list
  no longer renders a bare `()` / `(expected one of: )`.
- When no pairing channels exist, redirect to `openclaw devices list` /
  `openclaw devices approve` instead of failing opaquely.

AI-assisted (Claude Code).

(cherry picked from commit 44ec7580e2)
2026-07-14 01:52:17 -07:00
Agustin Rivera edf8b9037d fix(voicecall): redact read-scoped status payloads (#97870)
* fix(voicecall): redact read-scoped status payloads

* fix(voicecall): make status assertion lint-safe

(cherry picked from commit 825aafac57)
2026-07-14 01:52:17 -07:00
Yuval Dinodia 4dc6dc7b6c fix(google-meet): fall back to manual OAuth paste when callback port is occupied (#96492)
The Google Meet OAuth login binds a fixed localhost:8085 callback listener
and let listener failures propagate, so meet auth login aborted entirely when
port 8085 was already in use. The sibling Gemini CLI OAuth path already
recovers by switching to the manual copy/paste flow on EADDRINUSE/listen
errors; bring Google Meet to parity by catching listener errors and reusing
the existing manual-paste handler instead of failing the login.

(cherry picked from commit 38ab207591)
2026-07-14 01:52:17 -07:00
lin-hongkuan cff2bd8030 fix(secrets): strip control characters from secret input (#96444)
* fix(secrets): strip control characters from secret input

* chore: retrigger PR checks

* fix(web-content): strip controls from provider secrets

---------

Co-authored-by: lin-hongkuan <lin-hongkuan@users.noreply.github.com>
(cherry picked from commit bc7f0f1223)
2026-07-14 01:52:16 -07:00
Yuval Dinodia 1de19812c4 fix(compaction): count bashExecution and summary turns in pre-prompt overflow precheck (#97861)
estimateMessageTokenPressure special-cased toolResult, tool, and
assistant roles and otherwise read record.content. bashExecution stores
its payload in command/output and branchSummary/compactionSummary store
theirs in summary, so record.content was undefined and those turns
scored as bare boundary overhead. The provider request expands them via
convertToLlm into full user text, so bash-heavy sessions skipped the
preflight overflow gate and submitted oversized prompts.

Estimate each affected role from the exact text convertToLlm renders:
bashExecutionToText for bash turns (zero for excludeFromContext records,
which convertToLlm drops), and the summary prefix/suffix plus summary
text for the two summary roles.

(cherry picked from commit 24626e5266)
2026-07-14 01:52:06 -07:00
Alix-007 4b5592e62b fix(cli): bound and redact generated video downloads
Bounds the no-output generated video download path and redacts provider URLs from HTTP failure errors.

(cherry picked from commit 561c713bb1)
2026-07-14 01:52:06 -07:00
frank-beans cc05b93c39 Preserve provider settings during onboarding updates (#100107)
* Preserve provider settings during onboarding updates

* fix(onboarding): clear omitted request auth

* fix(onboarding): retain canonical provider keys

* fix(onboarding): canonicalize provider updates

* fix(minimax): preserve models across provider aliases

* fix(minimax): preserve secret references during onboarding

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 664464c750)
2026-07-14 01:52:05 -07:00
zw-xysk 3b9caa7d49 fix(feishu): keep top-level appSecret SecretRef active for the implicit default account (#96965)
When a Feishu channel has top-level appId/appSecret using SecretRef
format and sub-accounts with their own inline appSecret, the secrets
resolver marks the top-level SecretRef as inactive because
isBaseFieldActiveForChannelSurface only checks whether any explicit
account inherits the field.

Feishu account listing always creates an implicit default account from
top-level credentials.  The fix detects this implicit default account
and keeps the top-level appSecret active accordingly, without changing
the shared channel secret helper semantics for other channels.

Fixes #96929

Signed-off-by: 赵旺0668001248 <0668001248@duomai.com>
(cherry picked from commit 4e7992cc9b)
2026-07-14 01:52:05 -07:00
Masato Hoshino 9fcd5d0b10 fix(commitments): preserve extraction batch on transient failure (#89817)
A drained extraction batch is spliced off the queue before the extractor
runs. On a non-terminal failure the batch was never restored, so those
items were silently lost and never retried. Restore the batch to the
front of the queue (original order) on non-terminal errors and rethrow so
the caller still logs; terminal model/auth errors keep the existing
cooldown drop/stop behavior. Also ensure the single-slot debounce
schedules a drain from the overflow branch, so a queue left full by a
restored batch still gets retried instead of being stuck.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit be0c40bad2)
2026-07-14 01:52:05 -07:00
Wynne668 02b0020d37 fix(mattermost): strip internal tool-trace banners from outbound text (#98693)
* fix(mattermost): strip internal tool-trace banners from outbound text

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(mattermost): prove outbound sanitizer send path

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 1ef4544871)
2026-07-14 01:52:05 -07:00
Wynne668 34686282d6 fix(sms): strip internal tool traces from replies
(cherry picked from commit 06b841fa58)
2026-07-14 01:52:05 -07:00
Masato Hoshino 6dc6789e75 fix(slack): sanitize internal tool-trace lines from outbound text (#97367)
Wrap the slack outbound sanitizeText hook with sanitizeAssistantVisibleText so assistant internal tool-trace scaffolding is stripped before delivery, matching the sibling channel fixes under #90684 (Telegram #95774, Google Chat #95084, IRC #97214).

(cherry picked from commit cd6d0f9b00)
2026-07-14 01:52:05 -07:00
Masato Hoshino ba74027ca5 fix(matrix): sanitize internal tool-trace lines from outbound text (#97372)
Wrap the matrix outbound sanitizeText hook with sanitizeAssistantVisibleText so assistant internal tool-trace scaffolding is stripped before delivery, matching the sibling channel fixes under #90684 (Telegram #95774, Google Chat #95084, IRC #97214).

(cherry picked from commit 25490d4c42)
2026-07-14 01:52:04 -07:00
Masato Hoshino 1245f8af67 fix(irc): sanitize internal tool-trace lines from outbound text (#97214)
* fix(irc): sanitize internal tool-trace lines from outbound text

* fix(irc): sanitize internal tool-trace lines from outbound text

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
(cherry picked from commit ddedf13190)
2026-07-14 01:52:04 -07:00
wangmiao0668000666 6283802dbf fix(chutes-oauth-plugin): bound plugin JSON response reads
(cherry picked from commit 5723222bbb)
2026-07-14 01:51:57 -07:00
solodmd f3d4b174ad fix(anthropic-oauth): bound OAuth token endpoint response reads (#96644)
postJson reads the Anthropic OAuth token endpoint response body with
an unbounded await response.text(). A compromised or hijacked OAuth
endpoint can stream an arbitrarily large body and force the runtime
to buffer the entire payload before parsing — an OOM/DoS vector.

Replace with readResponseWithLimit at 16 MiB cap + TextDecoder decode
to match the sibling bounded-read pattern (provider-http-errors.ts:308).

Co-authored-by: Claude <noreply@anthropic.com>
(cherry picked from commit b1fae752f8)
2026-07-14 01:51:56 -07:00
NIO 2583a21d93 fix(plugin-sdk): bound Copilot token exchange JSON response reads (#97579)
* fix(plugin-sdk): bound Copilot token exchange JSON response reads

* test(plugin-sdk): add HTTP transport proof for Copilot token bounds

* fix(test): cast HTTP transport fetch mocks to typeof fetch

---------

Co-authored-by: NIO <nocodet@mail.com>
(cherry picked from commit 2f510a0ac1)
2026-07-14 01:51:56 -07:00
Yuval Dinodia 4c4914c76e fix(doctor): merge colliding model-ref map keys instead of dropping (#96544)
* fix(doctor): merge colliding model-ref map keys instead of dropping

When two retired model-ref keys in a models map upgrade to the same
current ref, rewriteModelRefMapKeys dropped the second entry silently
and still logged a success line, so doctor --fix lost one entry's
params/streaming/alias/agentRuntime tuning while falsely reporting it
as upgraded.

Mirror the sibling provider-models-array merge path (#90047): deep-merge
the colliding entries preserving disjoint fields, keep the existing
value deterministically on a true field conflict, and push a merge or
collision change-log line instead of dropping.

* fix(doctor): block prototype keys when merging colliding model-ref map entries

mergeModelRefMapEntries copied arbitrary incoming config fields into a
plain object, so a colliding model entry carrying a __proto__ field could
mutate the merged entry prototype during legacy config migration. Skip
isBlockedObjectKey fields before assigning or recursing, matching the
shared config merge guard. Disjoint-field merging is unchanged.

* fix(doctor): preserve canonical model migration values

* fix(doctor): filter blocked keys on both merge sides and report retired source key

* fix(doctor): preserve colliding retired model settings

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
(cherry picked from commit 82871fe21b)
2026-07-14 01:51:56 -07:00
xingzhou 83739f918f fix(auth): recover from malformed API-key profiles (#97520)
* fix: reject malformed API-key auth profiles

* fix(auth): detect onboard command API-key variants

* fix(auth): reject malformed API-key flags

(cherry picked from commit fb7e10e868)
2026-07-14 01:51:56 -07:00
liuhao1024 c34dea1163 fix(auth): skip legacy OAuth repair when destination profile already exists (#97541)
When doctor --fix runs legacy OAuth profile id repair, it picks the
single non-legacy OAuth profile as the migration target. If that target
profile already exists as a separate user-configured account, the repair
unconditionally overwrites it, destroying the account's config
(displayName, email) and collapsing two distinct accounts into one.

Add a guard: if the destination profile id already exists in
cfg.auth.profiles, skip the repair entirely to preserve both accounts.
Also pass cfg to resolveAuthProfileMetadata so config-set displayName
is preserved when the repair does proceed.

Fixes #97522

(cherry picked from commit ee72fa7f5f)
2026-07-14 01:51:56 -07:00
wangmiao0668000666 a4d5aa1457 fix(transcripts): close stream on parse failure
(cherry picked from commit 94cb14b97e)
2026-07-14 01:51:56 -07:00
miorbnli 7be1e7f696 fix(sessions): fail fast on non-serializable JSONL root values (#97356)
serializeJsonlLine returned JSON.stringify(entry) without guarding the
undefined return case. When the root value is undefined, a function, or a
symbol, JSON.stringify returns undefined, which serializeJsonlEntry's template
literal coerced to the literal string "undefined" and wrote to disk. That is
not valid JSON, so parseJsonlEntries silently skipped the line — a fail-silent
loss of a transcript entry with no error log.

Throw a TypeError instead so the caller fixes the bad value before it reaches
the file. Circular references and BigInt already throw via JSON.stringify and
are unaffected. Null, primitives, and plain objects are unchanged.

Co-authored-by: Claude <noreply@anthropic.com>
(cherry picked from commit feba78fc8f)
2026-07-14 01:51:55 -07:00
NIO ca742f2703 fix(agents): retry compaction on provider-side AbortErrors (#97504)
Align inner compaction retry and compaction-safeguard provider fallback
with the #90908 signal.aborted pattern so undici disconnect AbortErrors
retry or fall back to LLM instead of producing degraded placeholder
summaries. Caller abort remains terminal.

Co-authored-by: NIO <nocodet@mail.com>
(cherry picked from commit 245c18da5a)
2026-07-14 01:51:38 -07:00
mikasa 8b6bcb9498 fix(agents): keep missing tool results on current model (#95543)
(cherry picked from commit b9c64142e2)
2026-07-14 01:51:38 -07:00
Peter Steinberger c077b89dd8 fix(agent-core): ignore truncated tool calls (#97140)
* fix(agent-core): ignore truncated tool calls

Co-authored-by: Galin Iliev <5711535+galiniliev@users.noreply.github.com>

* fix(agent-core): require explicit tool-call terminals

---------

Co-authored-by: Galin Iliev <5711535+galiniliev@users.noreply.github.com>
(cherry picked from commit 56259606d1)
2026-07-14 01:51:37 -07:00
Alix-007 2660016e61 fix(msteams): bound Microsoft Graph API response reads in graph-upload to prevent OOM (#97784)
* fix(msteams): bound Microsoft Graph API response reads in graph-upload to prevent OOM

* test(msteams): prove graph upload oversized JSON rejection

* test(msteams): tighten Graph response bound proof

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 0f775fa25e)
2026-07-14 01:51:27 -07:00
huangjianxiong c3a7a1911a fix(tlon): bound error response body reads to prevent OOM (#98496)
* fix(tlon): bound error response body reads to prevent OOM

Replace bare response.text() on non-ok paths with readResponseTextLimited
capped at 16 KiB so a hostile or misconfigured Urbit ship cannot force the
gateway to buffer an arbitrary-size error body into process memory.

Affected paths:
- pokeUrbitChannel (channel-ops.ts)
- channel.runtime.ts poke path
- sendSubscription (sse-client.ts)

* fix(tlon): fix lint issues in error-body-boundary test

- Remove unused beforeEach import
- Wrap if/else bodies in braces (curly)
- Use block body for Promise executors (no-promise-executor-return)

* fix(types): resolve pre-existing TS test type errors

- Fix TS2493 tuple type errors in server-cron-notifications and
  server-cron tests by adding explicit type annotations on mock.calls
- Fix TS2322 in anthropic.test.ts by adding as const to resource
  content block type

* chore: trigger CI

(cherry picked from commit 8abd5d4071)
2026-07-14 01:50:49 -07:00
Alix-007 19c6234639 fix(discord): bound requestDiscord happy-path response reads to prevent OOM (#97693)
* fix(discord): bound happy-path API response reads to prevent OOM

Replace the unbounded res.text() call in requestDiscord's success path with
readResponseTextLimited capped at 4 MiB. Discord channel message lists and
attachment payloads can accumulate to large sizes; without a cap the process
can exhaust available memory. The error path already used readResponseTextLimited
with DISCORD_API_ERROR_BODY_LIMIT_BYTES — this applies the same guard to the
happy path using a separate DISCORD_API_RESPONSE_BODY_LIMIT_BYTES constant
sized appropriately for valid API payloads.

* test(discord): upgrade to real HTTP server proof for bound requestDiscord

* fix(discord): remove unnecessary type assertion in bound test

(cherry picked from commit fca15641db)
2026-07-14 01:50:21 -07:00
Alix-007 7998802f5a fix(google-meet): bound Drive document export reads to prevent OOM (#97620)
* fix(google-meet): bound Drive document export reads to prevent OOM

* test(google-meet): return full guarded fetch result

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
(cherry picked from commit 2001b15f5b)
2026-07-14 01:50:21 -07:00
Alix-007 edafdcd882 fix(nextcloud-talk): bound external send/reaction response reads to prevent OOM (#96031)
* fix(nextcloud-talk): bound external send/reaction response reads to prevent OOM

Nextcloud Talk talks to self-hosted servers whose HTTP responses are not
trusted to be small. The send and reaction paths buffered three external
bodies without any byte cap:

- success JSON via await response.json()
- send error text via await response.text()
- reaction error text via await response.text()

A hostile or misbehaving Nextcloud endpoint could stream an unbounded body
(no content-length) into memory, pressuring or hanging the plugin/provider
path. Cap success JSON at 16 MiB via readResponseWithLimit and collapse error
bodies to an 8 KiB readResponseTextSnippet, cancelling the stream on overflow.
The 'message sent but receipt JSON unreadable -> unknown' fallback is
preserved (an over-limit body now also routes through the existing catch).

This is the symmetric counterpart to the #95103/#95108 response-limit
campaign, reusing the shared @openclaw/media-core helpers (newly re-exported
from plugin-sdk/response-limit-runtime for plugin consumers).

* fix(nextcloud-talk): bound error bodies via public readResponseTextLimited (no new plugin-SDK surface)

Re-exporting readResponseTextSnippet from plugin-sdk/response-limit-runtime
pushed the public plugin-SDK export count past its surface budget, failing
plugin-sdk-surface-report.test.ts. Drop that re-export and instead bound the
Nextcloud Talk send/reaction error bodies through the already-public
readResponseTextLimited (openclaw/plugin-sdk/provider-http), collapsing the
bounded 8 KiB prefix to a short, log-safe snippet locally. Behavior is
unchanged for callers; no new plugin-SDK surface is introduced.

Success JSON still reads through readResponseWithLimit (16 MiB cap). The
committed bounded-response-reads Vitest suite continues to prove the caps
hold against 17 MiB streamed bodies with no content-length.

* fix(nextcloud-talk): reuse shared readProviderJsonResponse for send success JSON

The send success receipt parsed JSON by hand via readResponseWithLimit + a
local NEXTCLOUD_TALK_JSON_MAX_BYTES cap + JSON.parse(TextDecoder.decode(...)),
duplicating the shared provider-http helper that the sibling room-info.ts and
bot-preflight.ts already use. extensions/AGENTS.md forbids re-implementing
shared helpers locally.

Swap the hand-rolled block for the one-stop
readProviderJsonResponse<{ ocs?: ... }>(response, "Nextcloud Talk send"), which
reads through the same bounded reader and throws on overflow/malformed JSON, so
the outer try/catch still keeps the "unknown" receipt and behavior is
equivalent. The error path keeps readResponseTextLimited (text, not JSON).

(cherry picked from commit d577cb2fe9)
2026-07-14 01:50:20 -07:00
wangmiao0668000666 ad47570182 fix(googlechat): replace unbounded response.json() with readProviderJsonResponse (#96772)
* fix(googlechat): replace unbounded response.json() with readProviderJsonResponse

Replace the local readGoogleChatJsonResponse and
readGoogleChatCertsResponse wrappers with the existing SDK helper
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http) so the
Google Chat API JSON responses are bounded at 16 MiB, matching the
non-streaming cap already used by 15+ other extensions.

What changed:
- extensions/googlechat/src/api.ts: readGoogleChatJsonResponse now
  delegates to readProviderJsonResponse. Removed the local try/catch
  wrapper.
- extensions/googlechat/src/auth.ts: readGoogleChatCertsResponse now
  delegates to readProviderJsonResponse. Error message preserved.
  Removed the local try/catch wrapper.

This PR applies the same pattern as Alix-007's #96042, #96038 (lmstudio,
provider JSON reads). No SDK promotion needed — readProviderJsonResponse
is already available in openclaw/plugin-sdk/provider-http.

* fix(googlechat): add inline bounded-read regression tests

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(googlechat): remove unused variable flagged by oxlint

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(googlechat): bound api error body reads

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
(cherry picked from commit 4f3d81b918)
2026-07-14 01:50:20 -07:00
mushuiyu886 45f9429115 fix #94040: [Bug]: nodes approve failed: GatewayClientRequestError: unknown requestId (#94452)
* fix(nodes): explain unknown approval request ids

* fix(nodes): keep stale request handling CI-clean

* fix(nodes): point stale approve hint at pending command

* fix(nodes): explain stale approval request ids

* fix(nodes): make stale approval guidance reliable

* fix(nodes): preserve stale approval error context

---------

Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit deb0ffdcdf)
2026-07-14 01:50:12 -07:00
zw-xysk 5e80bfc39b fix(tools): treat no-op writes and edits as terminal tool-loop failures (fixes #96983) (#97044)
* fix(tools): treat no-op writes and edits as terminal tool-loop failures

Fixes #96983

* fix(tools): treat no-op writes and edits as terminal tool-loop failures

Fixes #96983

* fix(tools): preserve valid sibling edits in mixed no-op batches

Fixes #96983

* fix(tools): terminate apply_patch no-ops safely

* fix(tools): validate no-op edits independently

* fix(tools): preserve no-op edit overlap checks

* fix(tools): preserve no-op patch file formatting

* fix(tools): preserve move no-op formatting

* fix(tools): narrow same-path move no-op typing

* fix(tools): distinguish edit no-op errors

* fix(tools): keep edit previews aligned with execution

* fix(tools): align no-op validation and formatting

* fix(tools): preserve empty patch and preview no-ops

* fix(tools): preview fuzzy edit no-ops cleanly

* fix(tools): isolate fuzzy-equivalent edit no-ops

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
(cherry picked from commit ab966c214b)
2026-07-14 01:50:12 -07:00
brokemac79 3aa5229691 fix: fallback on safe prompt timeouts (#96142)
(cherry picked from commit 0da26499da)
2026-07-14 01:50:11 -07:00
Radek Sienkiewicz 23f1f130f8 fix(cli): sync official plugins during update all (#96831)
Co-authored-by: ooiuuii <169449607+ooiuuii@users.noreply.github.com>
(cherry picked from commit 0247eab773)
2026-07-14 01:50:11 -07:00
Yzx 7a6c6efc10 fix: cron stream stalls fail over before job timeout (#96096)
* fix(agents): cap cron stream idle stalls

* fix(agents): preserve cron hostname timeout

* fix: bound cron idle timeout local exceptions

* fix: bound cron idle timeout local exceptions

---------

Co-authored-by: Radek Sienkiewicz <mail@velvetshark.com>
(cherry picked from commit 7fefc5ff58)
2026-07-14 01:50:11 -07:00
Yzx 71590a267f fix(cron): avoid gateway restart on setup timeout (#96396)
* fix(cron): avoid gateway restart on setup timeout

* fix(cron): avoid gateway restart on setup timeout

---------

Co-authored-by: Radek Sienkiewicz <mail@velvetshark.com>
(cherry picked from commit 19707cce1d)
2026-07-14 01:50:11 -07:00
张贵萍0668001030 183122fe42 fix(outbound): fail closed heartbeat reserved Telegram misses
(cherry picked from commit 3092b4fd0d)
2026-07-14 01:50:11 -07:00
sheyanmin 94bd74c5cd fix: recover channel after stop timeout in health monitor
When a channel stop times out (e.g. during a Telegram API outage),
the channel enters recoveryStopTimedOut state. The health monitor's
subsequent start call would set restartPending and return without
actually starting the channel.

If the stuck stop never completes, the channel stays in limbo forever
with the health monitor retrying every cycle but never recovering.

Fix: when the health monitor retries recovery (recoveryStartRequested
already set), clean up the stuck task state and allow the channel to
start normally.

Closes #94008

(cherry picked from commit 8b4be2fdd4)
2026-07-14 01:50:10 -07:00
rosenlo 27513d21ca fix(outbound): advance queue entry to unknown_after_send on mid-batch failure with send evidence
When a required-mode batch send fails mid-batch after an earlier payload
already succeeded, the wrapper catch in deliverOutboundPayloadsWithQueueCleanup
called failDelivery. failDelivery only bumps retryCount/lastError; it does
not advance recoveryState, so the entry stayed in send_attempt_started (set
earlier by markDeliveryPlatformSendAttemptStarted via onPlatformSendStart).

On the next Telegram reconnect, drainQueuedEntry sees send_attempt_started
and calls reconcileUnknownQueuedDelivery. When adapter reconciliation
misreports not_sent (the message was actually sent, per the outbound send
ok / messageId evidence), the entry is replayed and the user receives a
duplicate.

Fix: when the error carries send evidence (OutboundDeliveryError with
sentBeforeError === true and platformSendStarted === true), call
markQueuedPlatformOutcomeUnknown instead of failDelivery. This advances the
entry to unknown_after_send, which drain already routes through
reconcileUnknownQueuedDelivery, preserving the entry for adapter
reconciliation rather than leaving it in send_attempt_started for replay.

When there is no send evidence (sentBeforeError === false), failDelivery
remains correct: nothing reached the channel, so retrying is safe.

This is a third duplicate path distinct from #89812 (mirror best-effort)
and #92274 (subagent-announce-delivery retry); it is the outbound/deliver
wrapper catch, which neither prior fix covers.

Tests:
- regression: two payloads, first succeeds, second throws; asserts
  markDeliveryPlatformOutcomeUnknown called, failDelivery/ackDelivery not.
- guard: no send evidence; failDelivery still called.

(cherry picked from commit 71422a9a5a)
2026-07-14 01:50:10 -07:00
clawsweeper[bot] f04b0d8b1b fix(cron): preserve enabled-with-defaults failure alert through store roundtrip (fixes #96589) (AI-assisted) (#96615)
Summary:
- The PR preserves `failure_alert_disabled === 0` as the enabled-with-defaults failure-alert state and adds focused codec roundtrip tests.
- PR surface: Source +2, Tests +54. Total +56 across 2 files.
- Reproducibility: yes. At source level, current main encodes `failureAlert: {}` with `failure_alert_disabled = 0`, then decodes it as `undefined` when all explicit alert option columns are null.

Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.

Validation:
- ClawSweeper review passed for head bd9b2a1798.
- Required merge gates passed before the squash merge.

Prepared head SHA: bd9b2a1798
Review: https://github.com/openclaw/openclaw/pull/96615#issuecomment-4794949533

Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: liuhao1024 <11816344+liuhao1024@users.noreply.github.com>
Approved-by: takhoffman
(cherry picked from commit a21144d8a6)
2026-07-14 01:50:10 -07:00
Sarah Fortune 554b80de67 fix: surface provider authentication failures in channels (#96599)
* fix: surface provider authentication failures in channels

* fix: handle typed provider auth failures

---------

Co-authored-by: Sarah Fortune <sarah.fortune@gmail.com>
(cherry picked from commit 113d6f3c64)
2026-07-14 01:49:47 -07:00
Dallin Romney 43d833343f fix(gateway): fail closed at auth limiter capacity
(cherry picked from commit 2c7d423516)
2026-07-14 01:49:25 -07:00