Commit Graph

62866 Commits

Author SHA1 Message Date
Yuval Dinodia
150ca2fedd fix(agents): keep merged delivery routes account-bound (#98240)
* fix(agents): keep merged delivery routes account-bound

mergeDeliveryContext gated route-field crossing on channel only, so a
completion origin that knew its account but not a concrete target
inherited a different account's to/threadId on the same channel. A
subagent, cron, or media completion for bot-a could be addressed to
bot-b's chat but sent through bot-a (cross-account misroute) or dropped.

This restores the account-bound guard added in 1ed8592467 and removed as
collateral by 025db6cf9e (PR #89949); same-account and missing-account
merges still backfill so the media route-pin path is preserved. Restores
the deleted regression test.

* fix(agents): centralize account-bound completion routes

---------

Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
2026-06-30 18:32:35 -07:00
Vincent Koc
35af831fd0 Merge branch 'main' of https://github.com/openclaw/openclaw
* 'main' of https://github.com/openclaw/openclaw: (29 commits)
  refactor(gateway): trim attach grant implementation
  feat(gateway): scoped attach grants for external MCP loopback clients
  fix(gateway): iOS Talk treats SecretRef-backed API keys as missing (#98210)
  test(infra): add unit tests for SQLite number normalization (#98009)
  test(config): add unit tests for resolveExecCommandHighlighting (#98087)
  test(utils): add unit tests for chunkItems (#98219)
  fix(core): propagate caller env PATHEXT through isExecutableFile on Windows (#98093)
  fix(matrix): guard JSON.parse against malformed homeserver response bodies (#97973)
  fix(sms): guard Twilio JSON.parse against malformed API response bodies (#97999)
  Add Swedish mobile app localization (#98043)
  fix(anthropic): surface Discord pre-tool commentary
  fix(tui): correct disconnect copy for device scope upgrades (#98144)
  chore(ui): refresh fa control ui locale
  chore(ui): refresh nl control ui locale
  chore(ui): refresh vi control ui locale
  chore(ui): refresh th control ui locale
  chore(ui): refresh pl control ui locale
  chore(ui): refresh uk control ui locale
  chore(ui): refresh id control ui locale
  chore(ui): refresh tr control ui locale
  ...
2026-06-30 18:27:32 -07:00
Ayaan Zaidi
1241885db6 refactor(gateway): trim attach grant implementation 2026-06-30 18:22:05 -07:00
Cameron Beeley
2deb696ef4 feat(gateway): scoped attach grants for external MCP loopback clients
Per-session, TTL-bounded, revocable bearer grants (mcp-grant-store) let an external/interactive
harness reach the gateway's scoped MCP loopback tools without the cli-backend's process-global
token. A grant is a lower-trust boundary: it binds the session server-side AND fail-closes on every
caller-supplied context header (x-session-key plus message-channel/account/current-channel/thread/
source-reply/event-kind), so a grant holder can neither scope-shop the session nor spoof
delivery/action context into scoped tools or the message tool. New attach.grant/attach.revoke
operator methods mint/revoke grants and return the loopback MCP config. Owner/non-owner cli-backend
path unchanged.
2026-06-30 18:22:05 -07:00
ooiuuii
201eb9cd29 fix(gateway): iOS Talk treats SecretRef-backed API keys as missing (#98210)
* fix(gateway): resolve Talk SecretRefs for scoped native clients

* fix(gateway): constrain Talk secret materialization

* fix(gateway): redact Talk source provider secrets

* fix(gateway): satisfy Talk config lint

* docs(gateway): clarify Talk secret config payload

---------

Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
2026-06-30 20:17:33 -05:00
dwc1997
3669280b9a test(infra): add unit tests for SQLite number normalization (#98009)
* test(infra): add unit tests for SQLite number normalization

* fix: remove undefined param test, not in function signature
2026-06-30 18:15:38 -07:00
solodmd
4a200e6ecf test(config): add unit tests for resolveExecCommandHighlighting (#98087) 2026-06-30 18:15:31 -07:00
zengLingbiao
09ebc1d566 test(utils): add unit tests for chunkItems (#98219)
Add 8 test cases covering fixed-size array splitting, empty input,
size <= 0, size=1, size > length, exact division, readonly input
preservation, and fractional size behavior.
2026-06-30 18:15:24 -07:00
wendy
8028269d32 fix(core): propagate caller env PATHEXT through isExecutableFile on Windows (#98093)
* fix(core): propagate caller env PATHEXT through isExecutableFile on Windows

isExecutableFile hardcoded undefined when calling resolveWindowsExecutableExtSet,
ignoring any caller-provided custom env.PATHEXT. This meant resolveExecutablePath
and resolveExecutableFromPathEnv would fall back to process.env.PATHEXT even when
the caller supplied a different env with an extended PATHEXT (e.g. .PS1).

- Add optional options.env parameter to isExecutableFile
- resolveWindowsExecutableExtSet now reads from options?.env
- All 3 callers pass their available env through

Affects Windows deployments using sandbox/container environments where
PATHEXT differs from process.env (Docker Windows containers, CI runners, tests).
Fully backward compatible: undefined env falls back to process.env.PATHEXT.

* fix(core): also propagate caller env PATHEXT in node-host invoke resolver

- Fix sibling system.which resolver in src/node-host/invoke.ts:378
  to use caller env PATHEXT instead of process.env only
- Add comprehensive Windows-mocked tests for caller env PATHEXT
  propagation through isExecutableFile, resolveExecutableFromPathEnv,
  and resolveExecutablePath
- Tests cover: custom env accepted, fallback to process.env,
  path-separator and PATH-based resolution paths

* fix(core): also propagate caller env PATHEXT through node-host invoke resolver

- Add env?.PathExt and process.env.PathExt casing to both
  resolveWindowsExecutableExtSet and resolveWindowsExecutableExtensions
  for compatibility with callers using PascalCase env keys
- Isolate positive PATHEXT tests from process.env.PATHEXT by
  explicitly setting it to .TXT before each test, ensuring they
  prove caller env propagation rather than host env leak

* fix(core): add env?.PathExt casing to node-host system.which resolver

---------

Co-authored-by: wendy-chsy <wan.wenyan@xydigit.com>
2026-06-30 18:15:19 -07:00
lsr911
853a274f14 fix(matrix): guard JSON.parse against malformed homeserver response bodies (#97973)
Wrap JSON.parse(text) in MatrixAuthedHttpClient.requestJson with try/catch to prevent a malformed Matrix homeserver response from throwing an unhandled SyntaxError.

On parse failure, throw an Error with statusCode attached (matching the buildHttpError convention) so callers can handle it like any other Matrix API error.

Signed-off-by: lsr911 <liao.shirong@xydigit.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-06-30 18:15:14 -07:00
lsr911
6e98477ee4 fix(sms): guard Twilio JSON.parse against malformed API response bodies (#97999)
Wrap JSON.parse in parseTwilioListPayload and retrieveTwilioMessagingService with try/catch to prevent a malformed Twilio API response from throwing an unhandled SyntaxError.

- parseTwilioListPayload: return [] on parse failure (fail-safe for phone number listing)
- retrieveTwilioMessagingService: throw descriptive Error on parse failure

Note: parseTwilioApiError and parseTwilioSuccessPayload already had try/catch guards (lines 85-97, 104-121).

Signed-off-by: lsr911 <liao.shirong@xydigit.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-06-30 18:15:08 -07:00
Daniel Nylander
339d19b089 Add Swedish mobile app localization (#98043)
* feat: add Swedish mobile app localization

* fix: remove dead Swedish watch extension localization

* docs: document iOS metadata locale directories

---------

Co-authored-by: Daniel Nylander <daniel@danielnylander.se>
2026-06-30 18:15:04 -07:00
Marvinthebored
b3b51b0c91 fix(anthropic): surface Discord pre-tool commentary
Route Anthropic pre-tool narration through the commentary progress lane, preserve shared channel progress defaults, and keep Discord/Telegram reasoning gates explicit.

Thanks @Marvinthebored!
2026-06-30 18:12:07 -07:00
Dallin Romney
3eaaa2ca3c fix(tui): correct disconnect copy for device scope upgrades (#98144)
* fix(tui): correct disconnect copy for device scope upgrades

On disconnect, the TUI told users "Pairing required. Run `openclaw devices
list`, approve your request ID, then reconnect." This is misleading: the
gateway is asking for a device *scope upgrade* (the device is already
paired), and "pairing" points users at `openclaw pairing`, which only
handles chat DM pairing — a different subsystem.

- Reword the hint to name the scope upgrade and the actual recovery command
  (`openclaw devices approve --latest`), including the `--token`/`--password`
  escape hatch for when the device can't approve its own upgrade.
- Also match the gateway's "scope upgrade" disconnect reason, not just
  "pairing required".

AI-assisted (Claude Code).

* fix(tui): clarify device approval preview hint
2026-06-30 18:10:04 -07:00
github-actions[bot]
21e6fc948b chore(ui): refresh fa control ui locale 2026-07-01 01:09:00 +00:00
github-actions[bot]
db73ece2de chore(ui): refresh nl control ui locale 2026-07-01 01:08:55 +00:00
github-actions[bot]
0dcfbb09d8 chore(ui): refresh vi control ui locale 2026-07-01 01:08:41 +00:00
github-actions[bot]
bb0af61d20 chore(ui): refresh th control ui locale 2026-07-01 01:08:35 +00:00
github-actions[bot]
cb69ce7ba8 chore(ui): refresh pl control ui locale 2026-07-01 01:08:14 +00:00
github-actions[bot]
49edc0a8af chore(ui): refresh uk control ui locale 2026-07-01 01:08:05 +00:00
github-actions[bot]
c1aeaf9287 chore(ui): refresh id control ui locale 2026-07-01 01:08:00 +00:00
github-actions[bot]
75bd44a94b chore(ui): refresh tr control ui locale 2026-07-01 01:07:52 +00:00
github-actions[bot]
614032676d chore(ui): refresh it control ui locale 2026-07-01 01:07:33 +00:00
github-actions[bot]
1520d09807 chore(ui): refresh ar control ui locale 2026-07-01 01:07:21 +00:00
github-actions[bot]
5b5c6237c2 chore(ui): refresh fr control ui locale 2026-07-01 01:07:09 +00:00
github-actions[bot]
b4476ab72f chore(ui): refresh ko control ui locale 2026-07-01 01:07:04 +00:00
github-actions[bot]
6bdffa501b chore(ui): refresh ja-JP control ui locale 2026-07-01 01:06:54 +00:00
github-actions[bot]
006c2f7a2b chore(ui): refresh es control ui locale 2026-07-01 01:06:41 +00:00
github-actions[bot]
6b67ada87a chore(ui): refresh pt-BR control ui locale 2026-07-01 01:06:20 +00:00
Vincent Koc
f524b38f20 chore(deadcode): remove stale CLI testing aliases 2026-06-30 18:06:15 -07:00
Vincent Koc
630dbbb1a1 chore(deadcode): remove stale outbound testing aliases 2026-06-30 18:06:15 -07:00
Vincent Koc
ebbe606e4b chore(deadcode): remove stale ACP testing aliases 2026-06-30 18:06:15 -07:00
github-actions[bot]
ce9166d1cd chore(ui): refresh zh-CN control ui locale 2026-07-01 01:06:14 +00:00
github-actions[bot]
a9cb866f62 chore(ui): refresh de control ui locale 2026-07-01 01:06:07 +00:00
github-actions[bot]
34badde1d9 chore(ui): refresh zh-TW control ui locale 2026-07-01 01:06:02 +00:00
Ayaan Zaidi
7006e6fcac fix(web): reconcile transient commentary history 2026-06-30 18:03:39 -07:00
Ayaan Zaidi
90847a6525 fix(web): distill WebChat commentary persistence 2026-06-30 18:03:39 -07:00
ragesaq
5ad8456771 fix(web): order keyed commentary by timestamp with tool cards
Keyed preamble commentary was appended after the whole tool loop, so it relied solely on the final visible-time sort for placement and lost the insertion-order tiebreaker against tool cards. Splice each keyed commentary segment into the items list before the first item with a strictly-later timestamp, so a preamble that arrived before a later tool renders above that tool while the run is live (not only after final materialization). Tools sharing the commentary timestamp that are already visible stay above it. Adds a buildChatItems regression covering a keyed preamble between two tools.
2026-06-30 18:03:39 -07:00
ragesaq
789e0f939b feat(web): make WebChat commentary persistence configurable
Add a per-viewer 'Keep commentary' toggle (UiSettings.chatPersistCommentary,
default true) that controls whether keyed Codex preamble/commentary blocks
stay after the final answer or clear with it.

- Persist (default): keyed commentary materializes as durable blocks, current
  behavior, existing proof unchanged.
- Transient (toggle off): commentary stays live during streaming but is never
  materialized, so it disappears as the final message arrives. This is the
  transient-only behavior from #92236, now user-selectable instead of a
  maintainer-level either/or policy choice.

Single gating point in materializeVisibleStreamState (skip itemId-keyed parts
when persistCommentary is false); threaded from settings through the chat
event handler. Adds desktop + mobile header toggles and an en.ts label
(locale bundles regenerated via ui:i18n:sync, English fallback).

Tests: reconciliation persist/transient coverage, final-event handler honors
the setting, settings round-trip + header button assertions updated.
2026-06-30 18:03:39 -07:00
ragesaq
8af9bf9264 fix(web): label preamble proof blocks
Co-authored-by: Chisel <chisel@psiclawops.dev>
2026-06-30 18:03:39 -07:00
ragesaq
0aba518bbe fix(web): render WebChat preamble progress
Render Control UI item and preamble progressText events as chat stream segments and preserve pre-final stream commentary before appending final assistant messages. Keyed preamble segments stay independent from accumulated stream snapshots, so distinct same-text commentary items render intact.

Co-authored-by: Chisel <chisel@psiclawops.dev>
2026-06-30 18:03:39 -07:00
sunlit-deng
70cc909eea fix(openrouter): send explicit auth headers (#98187)
* fix(openrouter): send explicit auth headers

* test(openrouter): type stream mock calls
2026-06-30 18:03:14 -07:00
Josh Avant
47845e1651 Preserve chat soft line breaks on iOS (#98304) 2026-06-30 20:02:55 -05:00
headbouyJB
518937be4e fix(system-prompt): move exec-approval + Authorized Senders below cache boundary (#98267)
* fix(system-prompt): move exec-approval + Authorized Senders below cache boundary

buildExecApprovalPromptGuidance (channel-varying: CLI /approve vs native
approval UI) and buildUserIdentitySection / "## Authorized Senders"
(owner/identity-varying, dropped when minimal) were emitted into the static,
cacheable prefix *above* SYSTEM_PROMPT_CACHE_BOUNDARY. They fork the cacheable
prefix at ~token 1,460, invalidating client-side prefix caching for the rest of
the ~17.8K-token system prompt — causing minutes-long cold prefills on local
models (llama.cpp / MLX / Ollama) after any channel-varying cron/heartbeat turn.

Follow-on to #40256, which moved Messaging/Voice/Reactions below the boundary
but missed these two. Relocates both into the existing below-boundary
channel-guidance block. Pure cache-stability change with no behavioural change
(the guidance is position-independent for correctness). Extends the boundary
test to assert both sections sit below SYSTEM_PROMPT_CACHE_BOUNDARY.

Measured on a local deployment: shared cross-channel prefix grew ~1,460 ->
~15,486 tokens; post-cron interactive turns went from minutes to ~10s.

Fixes #98261

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6Hz9UEpxQ4W3d8XecvupH

* fix(system-prompt): suppress relocated exec-approval line under tool_call_style override

Addresses review (clawsweeper): the exec-approval guidance lived inside the
`tool_call_style` fallback, so a provider override of that section previously
replaced it. Relocating it below the boundary emitted it unconditionally, which
changed behaviour for providers/plugins that override `tool_call_style`. Gate the
relocated line on the absence of a `tool_call_style` override, restoring the
original "override replaces the whole section" contract. Extends the
provider-override test to assert the default approval line is suppressed when
the section is overridden.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6Hz9UEpxQ4W3d8XecvupH

* fix(system-prompt): tighten cache boundary proof

* fix(system-prompt): tighten cache boundary proof

* fix(system-prompt): tighten cache boundary proof

---------

Co-authored-by: headbouyJB <23249268+headbouyJB@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-06-30 18:00:21 -07:00
Dallin Romney
f749de4f0a fix(device-pairing): don't churn requestId on subset re-requests (#98145)
* fix(device-pairing): don't churn requestId on subset re-requests

A reconnect that re-requested a subset of an already-pending device
pairing request still superseded it with a fresh requestId. This is the
root cause of the "unknown requestId" failures during device approval:

1. A TUI connect files a broad scope-upgrade request; the owner copies its
   id from `openclaw devices list`.
2. `openclaw devices approve <id>` reconnects as a CLI probe that only needs
   `operator.pairing` — a subset of the pending scopes.
3. That subset re-request superseded the pending request with a new id, so
   the originally-listed id no longer existed and approve failed.

Refresh the existing request in place when the incoming request only asks
for roles/scopes a single pending request (same device key + role) already
covers. Escalations that request *more* than the pending request still
supersede with a fresh id, so the requestId stays bound to at least the
scope snapshot the owner saw (the existing security-motivated behavior and
its test are preserved).

AI-assisted (Claude Code).

* fix(device-pairing): align subset pairing with scope coverage
2026-06-30 18:00:12 -07:00
Peter Lee
e1724474d6 test(telegram): add regression test for forum topic message_thread_id with streamed reasoning (#94526)
* test(telegram): add regression test for forum topic message_thread_id with streamed reasoning

After thorough code tracing of all delivery paths (draft stream, durable,
non-durable, preview hooks), the current main branch already correctly
passes message_thread_id through all paths for the streaming reasoning +
final answer scenario in forum topics. The bug reported in #89352 may have
been resolved by earlier merged changes (media-path preservation,
draft/progress streaming, etc.).

This commit adds a focused regression test covering the combined
scenario to prevent future regressions.

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

* fix(telegram): assert forum thread at draft-stream boundary for both lanes

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 17:58:00 -07:00
lin-hongkuan
23527a456d docs: clarify source checkout Node floor (#97898)
* docs: clarify source checkout Node floor

* chore: refresh CI for PR #97898

---------

Co-authored-by: lin-hongkuan <lin-hongkuan@users.noreply.github.com>
2026-06-30 17:55:47 -07:00
welfo-beo
fc97e92ddd fix: surface node approval guidance from devices CLI (#98115)
* fix: surface node approval guidance from devices CLI

* fix: preserve node approval connection guidance

* fix: handle admin retry unknown device approvals

* fix: require stable node approval matches

---------

Co-authored-by: welfo-beo <187608477+welfo-beo@users.noreply.github.com>
Co-authored-by: welfo-beo <welfo-beo@users.noreply.github.com>
2026-06-30 17:55:30 -07:00
zengLingbiao
490a4c5d9b test(gateway): add unit tests for node wake state tracking and testing seam (#98205)
Add 17 unit tests for nodes-wake-state.ts covering:
- Exported wait/poll constants
- nodeWakeById Map operations (insert, overwrite, multi-entry, inFlight)
- nodeWakeNudgeById Map operations (independent tracking)
- clearNodeWakeState function (removal, no-op, scoped deletion)
- testing seam (getNodeWakeByIdSize, hasNodeWakeEntry, resetWakeState)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 17:53:56 -07:00
qingminlong
0d275c8c9d fix(android): clarify gateway auth recovery states (#98094)
* fix(android): clarify gateway auth recovery states

* fix(android): preserve retryable pairing recovery copy

* fix(android): prefer auth recovery detail before stale address

* fix(android): show auth recovery while approval loads
2026-06-30 17:53:51 -07:00