Commit Graph

14963 Commits

Author SHA1 Message Date
Vincent Koc
25a7708f19 fix(feishu): send card JSON message params as cards (#100883)
* fix(feishu): send plain card JSON as interactive cards

Co-authored-by: martingarramon <263922628+martingarramon@users.noreply.github.com>

* fix(clownfish): address review for gitcrawl-21-autonomous-drip-20260706 (1)

Co-authored-by: martingarramon <263922628+martingarramon@users.noreply.github.com>

* fix(feishu): preserve native card compatibility

Reported-by: @ZenoRewn
Co-authored-by: martingarramon <263922628+martingarramon@users.noreply.github.com>

* fix(feishu): fix native card fallback precedence

* fix(feishu): fix native card fallback precedence

---------

Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Co-authored-by: martingarramon <263922628+martingarramon@users.noreply.github.com>
2026-07-06 06:22:36 -07:00
xingzhou
5aa7c6267c fix(irc): monitor stays disconnected after IRC socket closes (#100799) 2026-07-06 06:07:12 -07:00
Vincent Koc
6418e196b1 refactor: remove unused internal exports (#100882) 2026-07-06 05:59:18 -07:00
Jesse Merhi
5cd71db85e fix(diagnostics-otel): route OTLP exports through env proxy
* fix(diagnostics-otel): route OTLP exports through env proxy

* fix(diagnostics-otel): harden OTLP proxy agent options

* fix(ci): refresh rebased gateway checks

* fix(ci): avoid proxy boundary scan
2026-07-06 22:52:22 +10:00
Vincent Koc
c3501761da test(qa): allow deleted progress in private final check 2026-07-06 05:49:48 -07:00
Peter Steinberger
ce36a13ad2 fix(browser): foreground tabs before screenshots (#100857)
Co-authored-by: Spencer Fuller <spencer.p.fuller@gmail.com>
2026-07-06 12:57:45 +01:00
Vincent Koc
e7d43db52f test(codex): make side tool abort test deterministic 2026-07-06 13:47:54 +02:00
Peter Steinberger
f53346944d feat: correlate native search outcomes in audit history (#98704)
* feat: correlate native search outcomes in audit history

Metadata-only audit ledger for agent runs and tool actions in the shared
state DB: stable event identity, closed action/status/error vocabularies,
one-way-hashed tool-call ids, never-inferred terminal outcomes for native
web-search (explicit completed/failed only; otherwise unknown), bounded
retention, audit.list gateway RPC and openclaw audit CLI. Squashed from
the 82-commit audit stack for replay onto current main.

* feat(audit): add audit.enabled config gate (default on)

The metadata-only audit ledger records by default: an audit trail enabled
only after an incident cannot explain the incident, and the rows are
strictly less sensitive than the transcripts every install already
stores. audit.enabled=false stops new writes at the gateway subscription
seam; audit.list and openclaw audit keep serving existing records until
they expire. Documented in the configuration reference, protocol page,
and CLI reference.

* fix: repair full-matrix CI findings after rebase

- break the dynamic-tools/dynamic-tool-execution import cycle by
  extracting resolveCodexToolAbortTerminalReason into a leaf module
- restore main's session-worktree protocol exports lost in the
  index.ts auto-merge
- register the audit event writer worker as a knip entry point
- docs table formatting; subagent wait-cancellation test scoped to its
  audit intent (outcome + timing) and advanced past main's new
  lifecycle-timeout retry grace
2026-07-06 12:30:12 +01:00
Peter Steinberger
827402243d feat: add Anthropic and OpenAI cost history (#100672)
* feat(providers): add admin cost history

* fix(ui): sync cron raw-copy baseline

* fix(usage): harden provider cost credentials

* fix(ui): refresh raw-copy baseline

* docs: refresh documentation map

* fix(ci): sync provider usage baselines

* fix(ui): hide zero-cost history bars

* docs(changelog): defer provider cost note
2026-07-06 12:06:55 +01:00
Ishan Godawatta
a53565f6df fix: normalise wiki lint targets (#100017)
* fix: normalise wiki lint targets

* fix: preserve wiki title queries
2026-07-06 04:03:15 -07:00
Peter Steinberger
e1595d5a96 fix(browser): clean up peer-scoped tabs on reset (#100792)
Co-authored-by: FMLS <kfliuyang@gmail.com>
2026-07-06 11:56:47 +01:00
Vincent Koc
17777b3a9f refactor: remove proven dead code across runtime surfaces (#100823)
* refactor: remove unused internal helpers

* refactor(ui): remove unused compatibility helpers

* refactor(android): remove unused talk cleanup shim

* refactor(android): remove orphaned legacy UI

* refactor: remove unused private exports

* refactor(docs-i18n): remove dead matcher and satisfy lint
2026-07-06 03:31:19 -07:00
xydt-tanshanshan
738654d20c fix(memory): add batch completed log after embedding batch finishes (#94732)
* [AI] fix(memory): add batch completed and batch failed logs for embedding ops

The embedBatchWithRetry function logged 'batch start' but never logged
'batch completed' or 'batch failed' after the embedding batch call,
leaving operators with no post-request feedback. When batches hang or
time out, only 'batch start' appears in logs with no diagnostic signal.

Add 'batch completed' log after runEmbeddingOperationWithTimeout success
and 'batch failed' log in the catch handler. This is an observability
improvement, not a functional fix for the underlying hang (#93312).

Related to #93312

* [AI] fix(memory): use formatErrorMessage for embedding batch error log

Replace String(err) with formatErrorMessage(err) in the batch failed
catch handler to redact sensitive provider error text (e.g. API keys
and tokens embedded in error messages) before logging.

Related to #94732

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-06 03:10:51 -07:00
Alex Knight
3221d43d89 fix(openai): image generation unavailable when openai provider set via config apiKey + custom baseUrl (#100745)
* fix(openai): treat a config apiKey as configured for image generation

The openai image provider's isConfigured only consulted env vars / auth
profiles (isProviderApiKeyConfigured) and considered a config apiKey only
inside that env/profile-gated branch. A provider apiKey supplied directly in
config (models.providers.openai.apiKey) — e.g. an AI-gateway token alongside a
custom baseUrl — was reported as not-configured, even though the generate path
resolves exactly that credential via resolveApiKeyForProvider and honors the
config baseUrl. This made image generation behave differently from chat models,
which authenticate purely from provider config.

Recognize a config apiKey as configured so image generation works purely from
config, like chat, with no OPENAI_API_KEY env var or auth profile. Env/profile
and Codex/ChatGPT-OAuth branches are unchanged. Formatting verified with oxfmt
--check (no node_modules in this worktree); full tests run in CI/Testbox.

* fix(openai): require a non-empty config apiKey for image readiness

* fix(openai): normalize config apiKey readiness via hasConfiguredSecretInput

---------

Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
2026-07-06 19:54:44 +10:00
Alex Knight
7634c8118b fix(google): image generation unavailable when google provider set via config apiKey + custom baseUrl (#100779)
* fix(google): image generation unavailable when google provider set via config apiKey + custom baseUrl

* test(google): satisfy required baseUrl in provider config fixture

* fix(google): normalize config apiKey readiness via hasConfiguredSecretInput

---------

Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
2026-07-06 19:54:10 +10:00
lzw112
22dfb15048 fix(telegram): add missing 'action' retry context for sendChatAction (#100762)
* fix(telegram): add missing 'action' retry context for sendChatAction

* fix(telegram): cover all sendChatAction retry paths

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-06 02:33:57 -07:00
Vincent Koc
c9abc75884 refactor: remove dead code and consolidate repeated paths (#100650)
* refactor(search): reuse provider setup finalizer

* refactor(android): remove unused helpers

* refactor(apps): remove unused Swift declarations

* refactor(diagnostics): reuse private reply delivery

* refactor(memory): reuse raw short-term store writer

* refactor(logbook): reuse batch row mapping

* refactor(scripts): centralize oxlint format policy

* refactor(memory): share qmd cache context hashing

* refactor(doctor): share auth issue classification

* chore(i18n): refresh native source inventory
2026-07-06 02:24:37 -07:00
Lu Wang
314c53b814 fix(telegram): extract canonical rich block text (#100570) 2026-07-06 09:12:25 +00:00
Peter Steinberger
d6801f23d4 feat(browser): restore driver "extension" via a loopback Chrome extension relay (no remote-debugging prompt) (#100619)
* feat(browser): restore driver "extension" via loopback Chrome extension relay

Reintroduces browser profile driver "extension" (removed in 2026.3.22) as a
loopback relay that drives the user's signed-in Chrome through an MV3 extension
instead of the remote-debugging port. This avoids Chrome's blocking "Allow
remote debugging?" prompt, which cannot be clicked when the operator drives
OpenClaw from a phone. Automated tabs live in an "OpenClaw" tab group (the
consent boundary), mirroring the Codex/Claude-in-Chrome model.

- relay bridge synthesizes the CDP browser target surface for Playwright
  connectOverCDP and forwards session-scoped commands to chrome.debugger
- relay server binds loopback only; both sides authenticate with a token
  derived (HMAC-SHA256) from gateway auth, so the raw credential never reaches
  Chrome; extension origin + loopback Host checks guard the upgrade
- built-in "chrome" profile; distinct relay ports per extension profile;
  relay reconciles on auth rotation / cdpPort change and prunes removed profiles
- doctor + status surface the extension transport; doctor keeps repairing the
  retired relay endpoint URL on legacy "extension" profiles

Refs #53599

* feat(browser): bundle the OpenClaw MV3 Chrome extension

Thin MV3 extension (chrome-extension/): a WebSocket client to the loopback
relay plus chrome.debugger forwarding and OpenClaw tab-group management. All
CDP target synthesis lives server-side in the relay bridge, so the extension
stays a dumb transport (the removed 2026.3 extension put that logic in a
1000-line untestable service worker). Popup handles pairing and per-tab share
toggle; `openclaw browser extension path|pair` load and pair it. A build copy
hook stages it into dist so the load path is stable.

Refs #53599

* docs(browser): document the Chrome extension profile

Adds docs/tools/chrome-extension for the restored extension driver (install,
pair, tab-group consent model, security posture) and wires it into the browser
docs profile section and nav.

Refs #53599

* feat(browser): make the extension relay work on remote browser nodes

Derives the relay auth token from a host-local secret in the credentials dir
(created on first use) instead of gateway auth. Each machine that runs a
browser — the gateway host and every browser node host — owns its own token, so
the extension pairs with whichever machine hosts its Chrome and no gateway
credential travels to a node. The node host already runs the shared browser
control bootstrap, so this is all that was missing for cross-machine control.

Also removes the "relay needs gateway auth before it can start" failure mode:
startup and `openclaw browser extension pair` ensure the secret exists.

Refs #53599

* fix(browser): harden relay secret creation and satisfy CI lint/typecheck

- Make the host-local relay secret creation atomic (O_CREAT|O_EXCL + adopt the
  winner on EEXIST) so the gateway service and `extension pair` CLI cannot mint
  divergent tokens on a fresh host (would 401 until restart); credentials dir
  created mode 0700. (adversarial review finding)
- Resolve type-aware oxlint findings across the relay + extension: unknown catch
  vars, addEventListener over ws.on* in the MV3 worker, void async listeners,
  drop useless returns/spreads, Object.assign over map-spread, safe ws frame
  decode (Buffer[]/ArrayBuffer), toSorted.
- Add extensionRelayDefaultPort/extensionRelayPorts to remaining test config
  literals; type the extension relay-core module (.d.ts, excluded from dist);
  regenerate docs_map.

* fix(browser): satisfy OpenGrep security policy on the relay

- Hash both operands before timingSafeEqual so token comparison has no
  length short-circuit (GHSA-JJ6Q-RRRF-H66H).
- Bound the relay WebSocketServer with maxPayload (64 MiB, headroom for CDP
  screenshots/bodies) against oversized frames (GHSA-VW3H-Q6XQ-JJM5).
- Rewrite the config test env helper to avoid the skill-env-host-injection
  shape (GHSA-82G8-464F-2MV7); it is a test-only env swap.
2026-07-06 10:08:27 +01:00
xingzhou
37022833c5 fix(anthropic): include Fable 5 in context1m wrapper (#100572) 2026-07-06 02:07:36 -07:00
zhangqueping
adc4136a3b fix(memory-wiki): strip fenced code and inline code before wikilink extraction (#98095)
* fix(memory-wiki): strip fenced code and inline code before wikilink extraction

The wikilink extractor in extractWikiLinks previously scanned
the full markdown content including fenced code blocks and
inline code spans.  Literal [[...]] syntax inside code regions
(e.g. bash test syntax, Scala generics like
Future[Option[User]]) produced false-positive broken-wikilink
lint warnings.

Add FENCED_CODE_BLOCK_PATTERN and INLINE_CODE_PATTERN and
strip those regions from the searchable text before running
the Obsidian and Markdown link regexes.  Five regression tests
cover backtick-fenced, tilde-fenced, 6-backtick-fenced, and
inline code scenarios plus a full vault lint round-trip.

Fixes #97945

* fix(memory-wiki): accept longer closing fence in code block stripping

The FENCED_CODE_BLOCK_PATTERN used a regex backreference (\1)
that required the closing fence to be exactly identical to the
opening fence.  CommonMark allows the closing fence to be the
same character type and at least as long — e.g. ``` opening
with ```` closing is valid.  Switch to a function-based
replacement that compares fence character type and length.

Add regression test for the longer-closing-fence case per
ClawSweeper review feedback (#98095).

* style(memory-wiki): add braces to if-body in fence replacement callback

Fixes ESLint curly rule violation at line 403.

* fix(memory-wiki): replace fence regex with line scanner for wikilink extraction

Replace FENCED_CODE_BLOCK_RE regex/callback with a line-by-line scanner
that keeps searching past invalid fence-looking lines (e.g. a shorter
``` line inside a longer `````` block) until a valid closing
fence of the same character type and at least as long is found.

Also handles tilde fences and longer closing fences per CommonMark spec.

🦞 diamond lobster: L2 evidence (5 real function-call scenarios, all passing)

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

* fix(memory-wiki): use CommonMark code masking

---------

Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
2026-07-06 02:00:12 -07:00
lin-hongkuan
9607c3a2bf fix(discord): preserve text after oversized uploads (#99577)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: lin-hongkuan <lin-hongkuan@users.noreply.github.com>
2026-07-06 09:25:05 +01:00
chenxiaoyu209
5e64c61368 fix(google): resolve thought_signature gate for Gemini latest aliases (#100605) 2026-07-06 09:12:35 +01:00
Momo
e0d23cfc5a fix(telegram): dedupe visible assistant prompt context (#100573)
Summary:
- Merged fix(telegram): dedupe visible assistant prompt context after ClawSweeper review.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(telegram): align directive reply prompt timestamps

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

Prepared head SHA: 5c4cc7245e
Review: https://github.com/openclaw/openclaw/pull/100573#issuecomment-4890518598

Co-authored-by: momothemage <niuzhengnan@163.com>
Approved-by: momothemage
2026-07-06 08:11:08 +00:00
Alix-007
bf5c9d1748 fix(feishu): bound Feishu API JSON response reads to prevent OOM (#97782)
* fix(feishu): bound Feishu API JSON response reads to prevent OOM

Replace the bare `response.json()` in `fetchFeishuJson`
(`extensions/feishu/src/app-registration.ts`) with a `readResponseWithLimit`
call capped at 16 MiB. A misconfigured or adversarial Feishu endpoint that
streams an unbounded body previously had no defence; the bounded reader now
cancels the stream at the cap and throws a labelled `feishu.api` error.

Tests: over-cap (32 MiB stream, no Content-Length — stream cancelled, error
matches feishu.api), under-cap (chunked valid JSON — parsed and returned),
and malformed-JSON (labelled feishu.api error). All five tests pass.

* fix(feishu): delegate JSON reads to provider helper

* test(feishu): add real node:http server proof for readProviderJsonResponse bound

* test(feishu): fix lint errors in real HTTP server proof (curly + no-promise-executor-return)

* test(feishu): prove bound reads through SSRF guard

* fix(feishu): satisfy overloaded LookupFn type in hermetic test lookup stub
2026-07-06 01:06:08 -07:00
NIO
3b189dfd34 fix(qa-lab): bound Telegram live transport JSON response reads (#99151)
* fix(qa-lab): bound Telegram live transport JSON response reads

* fix(scripts): satisfy oxlint in qa-lab telegram bound proof

* chore: drop local proof script from qa-lab telegram bound PR

---------

Co-authored-by: NIO <nocodet@mail.com>
2026-07-06 00:59:59 -07:00
lin-hongkuan
d0fdfe845b fix(codex): return JSON-RPC codes for handler errors (#100713)
Co-authored-by: lin-hongkuan <lin-hongkuan@users.noreply.github.com>
2026-07-06 08:59:20 +01:00
lwy-2
f1f8c1ed16 fix(providers): bound successful OAuth and webhook responses (#98098)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-06 08:58:58 +01:00
xingzhou
cecb6cf600 fix(openai): keep missing-auth hint on default model (#100579) 2026-07-06 08:56:20 +01:00
lzw-xydt
7b68306949 fix(telegram): add missing "edit" retry context for editMessageTelegram (#100543) 2026-07-06 00:46:37 -07:00
Peter Steinberger
9302c80ca6 fix(openai): route mp3 tts as voice messages (#100715)
Co-authored-by: Hemantsudarshan <hemanthsudarshan2002@gmail.com>
2026-07-06 08:34:08 +01:00
Peter Steinberger
d7d19a3a8e fix(openai): reuse Codex auth for realtime voice (#100671)
Co-authored-by: Peter Steinberger <steipete@openai.com>
2026-07-06 08:08:26 +01:00
Miorbnli
7d939b6456 fix(memory-core): guard qmd mcporter JSON.parse against non-JSON stdout (#98381)
* fix(memory-core): guard qmd mcporter JSON.parse against non-JSON stdout

runQmdSearchViaMcporter parsed mcporter subprocess stdout with JSON.parse
outside the runMcporter try/catch (qmd-manager.ts:2722). A non-JSON stdout
(daemon warning bleeding onto stdout, output truncated by maxOutputChars, CLI
killed early, or flag mismatch) threw a raw SyntaxError that propagated
uncaught out of runQmdSearchViaMcporter, surfacing in agent logs as a
context-free SyntaxError with no hint of the actual mcporter failure.

Wrap JSON.parse in try/catch and throw a typed Error carrying a stdout snippet
(matching the guard pattern already used in parseListedCollections in this
file, and the recent matrix #97973 / sms #97999 / signal #98073 /
telegram-ingress #98372 JSON.parse guard series).

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

* fix(memory-core): preserve cause in qmd mcporter JSON.parse guard

Add { cause: err } to the re-thrown Error to satisfy the preserve-caught-error
lint rule; the original SyntaxError is now chained, improving diagnosability.

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

* fix(memory-core): redact raw stdout from qmd mcporter error (security-boundary)

ClawSweeper flagged that the previous error message exposed raw mcporter
stdout (first 200 chars) before session visibility filtering, which could
leak sensitive content. Drop the stdout preview from the thrown message;
keep the original SyntaxError as `cause` for diagnostics so the parse-failure
reason is still reachable without surfacing unfiltered subprocess output.

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

* fix(memory-core): keep qmd mcporter error message generic (no raw stdout leak)

The SyntaxError thrown by JSON.parse embeds a snippet of the raw input in its
message (e.g. Unexpected token '<', then the raw bytes). Including that
SyntaxError message in the thrown Error would surface unfiltered mcporter
stdout before session visibility filtering. Drop the parse-error message from
the thrown Error; keep the original SyntaxError as cause for developer
diagnostics only.

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

* fix(memory-core): keep qmd mcporter cause generic (no raw stdout leak via formatErrorMessage)

formatErrorMessage walks the .cause chain into the user-visible path.
Keeping the JSON.parse SyntaxError on .cause leaked its embedded raw
stdout snippet through formatErrorMessage even with a generic message.
Give the cause a generic message too; the raw snippet no longer reaches
the user.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-06 06:57:41 +00:00
Peter Steinberger
037ad2bdfb feat(telegram): offer BotFather web app flow in setup help and docs (#100540) 2026-07-06 07:48:55 +01:00
Peter Steinberger
2830b3ef38 fix(browser): diagnose empty WSL2 Chrome replies (#100590)
* fix(browser): diagnose Windows CDP listener mismatch

Base the repair on #93481 while matching Chromium's IPv4-first, IPv6-fallback listener contract and keeping CDP exposure loopback-scoped.

Co-authored-by: ZengWen-DT <ceng.wen@xydigit.com>

* style(docs): format browser troubleshooting table

* docs: refresh browser troubleshooting map

* fix(browser): diagnose reset CDP replies

* docs: refresh browser troubleshooting map

---------

Co-authored-by: ZengWen-DT <ceng.wen@xydigit.com>
2026-07-06 07:42:02 +01:00
Wynne668
6378d5efcc fix(feishu): strip internal tool-trace banners from outbound text (#98705)
Part of #90684

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 06:33:16 +00:00
solodmd
1ec42c9acc fix(voyage): close response body stream when batch output JSONL parsing throws (#98840)
The batch output file download path creates a readline interface over a
Readable.fromWeb() response body stream. If JSON.parse throws on a malformed
JSONL line, the for-await loop exits via exception but the readline interface
and underlying Readable stream were never explicitly closed or destroyed,
leaving the HTTP response body stream dangling.

Extract the stream reading into , a testable helper
that wraps the iteration in a try-finally so both reader.close() and
inputStream.destroy() are always called, matching the pattern established in
#98493 for the same class of leak.
2026-07-06 06:32:50 +00:00
Peter Steinberger
20e6983bed fix(gateway): avoid default provider auth startup prewarm (#100667)
* fix(gateway): avoid default provider auth startup prewarm

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>

* docs(changelog): credit provider auth startup fix

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-06 07:32:13 +01:00
xingzhou
a13acacd3c fix(discord): keep command previews emoji-safe (#99539) 2026-07-06 05:40:39 +00:00
Marvinthebored
cbcd6a102c fix(clickclack): reply to a top-level message in-channel, not as a new thread (#100582)
* fix(clickclack): reply to a top-level message in-channel, not as a new thread

sendClickClackText routed any replyToId to createThreadReply, and the inbound
handler stamps replyToId = <triggering message id> on every reply. As a result
every reply to a top-level channel message opened its own thread, so the main
channel timeline showed nothing and the chat was effectively unusable.

Route a bare replyToId to the main channel as a quote-reply (quoted_message_id)
instead — matching the reply-to affordance of the Discord/Slack/Telegram
channels — and reserve threads for genuine thread context (an explicit threadId
or a thread-kind target). DM replies likewise quote-reply in the same
conversation. quoted_message_id is omitted when there is no reply context, so
plain sends are unchanged.

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

* test(clickclack): cover quote payload typing

---------

Co-authored-by: Marvinthebored <marvinthebored@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-05 22:27:27 -07:00
Sulaga
2b51c255f8 feat(tencent): add Tencent Hy3 provider (TokenHub and TokenPlan) (#99076)
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
2026-07-06 04:29:48 +00:00
Peter Steinberger
0acd851a3b feat(agents): add managed git worktree lifecycle (create/provision/snapshot/restore/GC) (#100535)
Centralized managed worktrees under <state-dir>/worktrees/<repo-fingerprint>/<name>
with branch-per-task (openclaw/<name>), .worktreeinclude provisioning, an optional
.openclaw/worktree-setup.sh repo hook, and a SQLite registry in the shared state DB.
Removal always snapshots the tree (untracked included, gitignored excluded) to
refs/openclaw/snapshots/<id>; restore rebuilds the branch at the original commit with
the snapshot content as uncommitted state. Lossless run-end cleanup, 7-day idle GC for
run-owned worktrees (manual exempt), orphan reconciliation, 30-day snapshot retention.
Surfaces: worktrees.* gateway RPC (operator.admin mutations), openclaw worktrees CLI,
Control UI page, plugin-SDK facade + Workboard kind:"worktree" materialization.

E2E-verified on Testbox: full create->work->remove->restore->gc lifecycle.
2026-07-06 05:24:58 +01:00
sunlit-deng
b7e5465f77 fix(signal): bound receive websocket payloads (#99992)
* fix(signal): bound receive websocket payloads

* docs(signal): explain receive frame cap

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-06 05:10:57 +01:00
Peter Steinberger
f53103de72 fix(skills): make Skill Workshop lifecycle approvals decidable and non-wedging (#91266, #94249, #93173) (#100498)
Approval wait now fits inside the Codex dynamic-tool watchdog (70s +10s
gateway grace under the 90s kill), approval cards carry proposal id,
skill name, description, file count, and body size (spoof-safe
rendering), and timeouts return a structured pending-not-failed outcome
instead of a bare error. Expired requests cannot execute late; no
auto-apply; generic plugin approvals unchanged.
2026-07-06 04:54:48 +01:00
Peter Steinberger
07e2d633cc feat: show auto-detected provider plans and billing (#100520)
* feat(providers): auto-discover usage billing

* feat(ui): show provider plans and billing

* fix(ui): translate provider billing labels
2026-07-06 04:53:09 +01:00
NIO
a4261cac4d fix(tlon): bound external image upload reads (#100374)
* fix(tlon): bound external image upload reads

* fix(tlon): make upload Blob construction type-clean

* test(tlon): trim upload fixture result

* docs(changelog): note Tlon upload bounds

---------

Co-authored-by: NIO <nocodet@mail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-06 04:44:33 +01:00
sunlit-deng
ae53570ea8 fix(browser): notify agent when click triggers download (#93307)
* fix(browser): drain download saves and use monotonic cursor for act response

- Add drainPendingDownloadSaves() to wait for in-flight saveAs before sampling
- Use monotonic downloadSeq cursor instead of bounded-list length
- Propagate downloads info in POST /act response for click/batch/evaluate

Fixes #93250

* fix(lint): add braces around single-line if returns

Fixes eslint(curly) failures in drainPendingDownloadSaves and
pickNewDownloads. PR #93307 required CI gate.

Ref: ClawSweeper P1 review finding

* fix(browser): scope act download metadata to action

* fix(browser): broadcast downloads to all active captures to prevent misattribution

When concurrent /act calls overlap on the same page, using
state.actionDownloadCaptures.at(-1) assigned downloads to the wrong
action's capture. Push managed save promises to all active captures
so the triggering action always receives its download metadata.

Also adds regression tests: broadcast-to-all-captures, sequential
capture isolation, and strengthen the dispose test to assert no
re-capture after disposal.

* fix(browser): prevent unhandled rejection when download capture action throws before drain

Move managedSave.catch() before the captures-branch check so the
rejection handler always runs, preventing an unhandled promise
rejection when the action throws before drain() is called. Simplify
the handler by removing the now-dead return + catch at the bottom.

* fix(browser): type downloads in BrowserActResponse, fix lint unused var

- Add optional downloads field to BrowserActResponse type contract so
  typed callers of browserAct() can consume the new payload without casts.
- Remove unused afterDispose variable in pw-session tests (lint fix).

* fix(test): correct post-dispose download assertion

capture.promises is not cleared by dispose(), so re-draining a disposed
capture still returns pre-dispose results. This is benign — callers
should drain before disposing. Update the test to assert the actual
behavior (still shows old results, new download not captured).

* test(browser): cover /act download metadata response

* refactor(browser): report action-owned downloads safely

* fix(browser): close action download ownership races

* test(browser): type action download capture mock

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-06 04:07:16 +01:00
Gorkem Erdogan
39916560e4 improve(auto-reply): render chat history since last reply as per-message prose (#100366)
* fix(auto-reply): render chat history since last reply as per-message prose

The inbound chat-history block dumped batched history as a raw JSON array, which models read poorly compared to the chat-window block's per-message prose. Reuse the existing formatChatWindowMessage renderer for history entries so both blocks share one shape, keep the untrusted framing label, and keep media rendered as a bare content-type tag so local paths and URLs stay redacted. Teach the metadata stripper to consume the new prose block form.

* fix(auto-reply): preserve every media content type in chat-history prose

The prose chat-history renderer only forwarded the first attachment's
content type per history message, dropping the rest for entries with
multiple media items. Join all bounded content types instead, and
regenerate the prompt snapshot fixture this changes.

* test(qa-lab): accept prose pending history

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-06 03:59:29 +01:00
Peter Steinberger
443c582949 fix(ios): restore in-flight runs after reconnect (#100277)
* fix(ios): restore in-flight chat runs from gateway history

Restore active Apple chat ownership across reconnect, foreground, and sequence-gap recovery using the existing chat.history snapshot. Preserve agent/session scoping and Gateway user-turn identity across Codex and Copilot mirrors, including current offline-cache integration.

* fix(ios): restore in-flight chat runs from gateway history
2026-07-06 03:23:38 +01:00
NIO
19f5a4a0bb fix(tlon): bound urbit scry JSON response reads (#100376)
* fix(tlon): bound urbit scry JSON response reads

* fix(tlon): preserve bounded scry diagnostics

* refactor(tlon): tighten scry boundary proof

* docs(changelog): stabilize Tlon response entry

* docs(changelog): close out maintainer batch

* chore(changelog): defer batch closeout

---------

Co-authored-by: NIO <nocodet@mail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-06 03:22:59 +01:00