Commit Graph

37038 Commits

Author SHA1 Message Date
snowzlmbot
2f98e1fdb5 fix(telegram): address rich fallback proof review 2026-07-07 14:14:03 +05:30
snowzlmbot
982328218b fix(telegram): harden rich send fallback and typing breaker
- Raise typing-breaker default from 2 to 5 consecutive failures via a
  named constant, keeping explicit overrides intact.
- Extend rich-plain-fallback trigger map to classify
  RICH_MESSAGE_CONTENT_REQUIRED alongside existing invalid-entity
  errors so both durable and streaming send funnels benefit.
- Add empty rendered-rich-HTML guards before sendRichMessage in both
  the durable chunk loop (send.ts) and the streaming delivery funnel
  (delivery.send.ts), preventing doomed Bot API calls and preserving
  later valid chunks.
- Add regression tests for the default typing breaker, delivery-side
  and durable-side RICH_MESSAGE_CONTENT_REQUIRED fallback behavior.
2026-07-07 14:14:03 +05:30
LiLan0125
686b778468 fix(backup): isolate retry temp archives (#101449)
* fix(backup): isolate retry temp archives

Closes #101382

* fix(backup): remove unused retry path initializer

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-07 01:29:45 -07:00
LZY3538
a6352f9356 fix(status): surface auto-fallback model in status and session_status (#96126) (#101337)
* @
fix(status): surface auto-fallback model in status and session_status (#96126)

When a session falls back to an alternate model via auto-fallback
(modelOverrideSource: "auto"), both `openclaw status` and `session_status`
silently showed the active fallback model without indicating it differs
from the configured primary. The mismatch gate used
hasUserPinnedModelSelection() which returns false for auto-fallback.

- status.summary.ts: widen mismatch gate from hasUserPinnedModelSelection
  to entry?.modelOverride != null; emit distinct "fallback selected"
  reason alongside existing "session override"
- status.command-sections.ts: add fallback-specific wording ("auto
  fallback" / "check provider availability") while keeping the
  modelSelectionReason filter intact (no false-positive null-reason rows)
- status-message.ts: add sessionHasAutoFallback detection for the
  session_status RPC path; show "auto fallback" / "check provider" label
  instead of "pinned session" / "clear /model default"

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

* fix(status): narrow fallback detection to real fallback provenance

Replace entry?.modelOverride != null with
hasSessionAutoModelFallbackProvenance(entry) to avoid mislabeling
configured subagent automatic model selections as provider fallback.

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

* fix(status): distinguish configured models from fallback

Co-authored-by: LZY3538 <liu.zhenye@xydigit.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 09:17:58 +01:00
Petros Dhespollari
6894bb7508 fix(gateway): persist media metadata in agent.request transcripts (#86936)
* fix(gateway): persist agent request transcript media

Route inline and offloaded agent.request images through the canonical user-turn transcript recorder across embedded, CLI, and ACP runtimes. Share ordered media persistence with chat.send and cover media-only empty-reply turns.

Co-authored-by: Petros Dhespollari <info@peterdsp.dev>

* fix(gateway): avoid transcript media shadowing

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 09:16:15 +01:00
Peter Steinberger
82b0f7cdc8 perf(test): use lightweight thinking fallback fixture 2026-07-07 03:59:28 -04:00
pick-cat
e72dadbb3b fix(anthropic): resolve thinking as disabled when legacy budget is below 1024 (#101415)
* fix(anthropic): resolve thinking as disabled when legacy budget is below 1024

When adjustMaxTokensForThinking collapses the thinking budget below the
Anthropic minimum (1024), option resolution now sets thinkingEnabled to
false instead of always forcing it to true. This keeps every downstream
consumer (payload, replay, temperature, tool-choice) consistent — they
all see the same disabled state instead of an enabled flag with a
missing or API-rejected thinking block.

|| → ?? in both builders is defensive: the resolution layer already
prevents invalid budgets from reaching the builder through the normal
path, but ?? preserves an explicit zero when the builder is called
directly.

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

* fix(anthropic): guard raw streamAnthropic builder path against sub-minimum budgets

Add budget guards in both Anthropic payload builders so direct
streamAnthropic and bundled-plugin callers (e.g. Mantle) that bypass
option resolution also get the disabled-state rule instead of producing
API-rejected { type: "enabled", budget_tokens: < 1024 } requests.

Add proof-anthropic-thinking-budget.mts driving real production
functions with terminal output and negative control.

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

* fix(anthropic): normalize legacy thinking budgets

Co-authored-by: Pick-cat <huang.ting3@xydigit.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 08:42:40 +01:00
pick-cat
41c0540bdc fix(doctor): expose default account routing in lint (#96147)
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: Pick-cat <266665499+Pick-cat@users.noreply.github.com>
2026-07-07 00:26:30 -07:00
Peter Steinberger
59bc7b0e16 perf(test): scope opencode context catalog warmup 2026-07-07 03:13:59 -04:00
Peter Steinberger
5ed8b81af7 fix(llm): project schema custom tools as functions (#101443) 2026-07-07 08:12:43 +01:00
Jason (Json)
f7e962d6e3 feat(cli): add openclaw promos to discover and claim ClawHub promotional model offers (#100236)
* feat: add openclaw promos CLI for ClawHub promotional model offers

* fix: harden promos claim auth validation and sanitize remote promo text

* fix: enforce promo window client-side and validate slug contract

* fix: shell-safe model ref contract and explicit --api-key override

* fix: hold promotion aliases to the models alias contract

* docs: document argv-credential contract and env alternative for promos claim

* fix: enforce provider plugin enablement on the credential-reuse claim path

* fix: require plugin install before credential-reuse shortcut in promos claim

* fix: run runtime plugin repair on promo defaults and harden identifier parsing

* fix: distinct message for contract-invalid promo aliases

* fix(cli): validate promotion plugin contracts

* fix(cli): recheck promotion window before claim

* feat(cli): surface ClawHub promotions in models list via the hosted feed

Passive discovery for promotional model offers. A cadence-gated (24h),
fail-silent conditional GET of ClawHub's immutable promotions feed
snapshot (If-None-Match -> 304, short 2.5s timeout, unauthenticated so
CDN caches stay unfragmented) is cached in two new shared-state-DB
tables, fully separate from update_check_state. models list renders an
'Available via promotion' group for live offers whose models are not in
the user's configured set (including the zero-row fresh-install path),
tags claimed models promo / promo ended from provenance recorded at
claim time, and prints a one-time notice per newly seen offer; promos
list and claim mark offers as seen. Machine outputs stay clean, snapshot
sequence is monotonic against stale edges, and claims still revalidate
against the live API so the kill switch always wins.

* style: satisfy lint on promotions feed additions

no-useless-fallback-in-spread on the optional request headers and
no-map-spread in claim-provenance row mapping.

* fix(cli): harden promotions feed cache

* fix(cli): honor live promotion validity
2026-07-07 01:10:42 -06:00
Wynne668
55fa22b482 fix(process): handle taskkill spawn errors (#101392) 2026-07-07 08:06:31 +01:00
Jason (Json)
c87225fb4a fix: keep owner tools available in WebChat (#101271)
* fix: keep owner tools available in WebChat

* fix: align WebChat owner policy checks
2026-07-07 01:00:24 -06:00
Vincent Koc
26c0285812 fix(plugins): keep source manifest metadata fallback 2026-07-07 08:42:39 +02:00
QiuYuang
769b8260cb fix(ports): ignore malformed lsof listener pids (#98505)
* fix(ports): ignore malformed lsof listener pids

* fix(infra): strictly reject malformed lsof pid tokens

Number.parseInt truncated tokens like "111abc" to 111, silently accepting
a corrupted lsof pid record. Switch to parseStrictPositiveInteger so the
whole token must be a valid positive integer, and restore the deduped
listener test that a prior change had replaced instead of extended.

* fix(cli): strictly reject malformed lsof pid tokens

Harden the force-free lsof parser to reject digit-prefixed garbage like
p111abc instead of truncating it to pid 111, and cover the sibling parser
with a focused regression test.

* fix(infra): strictly parse stale lsof pid tokens

Harden the stale gateway cleanup parser to reject digit-prefixed garbage
like p111abc instead of truncating it to pid 111, and add a focused
regression test without dropping the existing argv verification coverage.

* fix(ports): fail closed on malformed lsof pids

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-07 07:40:26 +01:00
xingzhou
de152b1f65 fix(plugin-sdk): align speech runtime packaging (#89899)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 07:38:41 +01:00
Truffle
5537bc9c4d fix(media): allow Bedrock SDK auth for image and PDF tools (#72092)
* fix(media): allow aws-sdk auth mode for image and audio/video paths

Media understanding tools failed for amazon-bedrock deployments using
auth.mode "aws-sdk" (BYOK via role/SSO/profile creds). Each path called
requireApiKey, which throws on the empty-key sentinel before the AWS SDK
credential chain can resolve creds at call time.

The image path (image.ts) resolves auth via getApiKeyForModel; the
audio/video paths route through resolveProviderExecutionAuth. Both now
mirror the chat path's allowMissingApiKeyModes allowance: when the
resolved key is empty and the mode is aws-sdk, execute keyless and let
the SDK resolve credentials. The image path skips setRuntimeApiKey so no
empty-string secret is persisted; audio/video return the kind:"none"
execution auth so the runner bypasses key rotation.

Closes #72031

* fix(media): cover Bedrock PDF SDK auth

* fix(pdf): register plugin completion streams

* fix(media): recognize Bedrock SDK tool auth

* chore: move release note to PR

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 07:37:32 +01:00
Alix-007
3929c52069 fix(agents): keep structured prompt summaries UTF-16 safe (#101311)
* fix(agents): keep structured prompt summaries UTF-16 safe

* chore: align prompt summary branch with current main

* fix(agents): keep structured summaries UTF-16 safe

* chore: keep release notes in PR context

* chore: keep release notes in PR context

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-07 07:32:05 +01:00
mushuiyu886
92e25df271 fix(agents): avoid repeated item progress snapshots (#101042)
* fix(agents): avoid repeated item progress snapshots

* chore: align ACP branch with current main

* fix(agents): deduplicate ACP parent progress

* chore: keep release notes in PR context

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-07 07:31:13 +01:00
SunnyShu
13f8dfae86 fix(outbound): retry proven pre-connect failures (#101024)
* fix(outbound): retry proven pre-connect failures

Co-authored-by: 0668000539 <shu.zongyu@xydigit.com>

* refactor(infra): keep retry attempt metadata internal

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 07:23:54 +01:00
Vincent Koc
f0564943a7 docs(openai): refresh realtime 2.1 examples 2026-07-06 23:22:33 -07:00
Peter Steinberger
7b366e16b0 fix: Windows CLI backends fail through npm shims (#101378)
* fix(process): resolve Windows npm CLI shims directly

Co-authored-by: wendy-chsy <wan.wenyan@xydigit.com>

* docs(changelog): note Windows CLI shim fix

* docs(process): explain Windows shim boundary

* chore: keep release changelog owner-only

* test(process): isolate Windows shim resolution

* fix(process): classify Windows forwarding shims safely

---------

Co-authored-by: wendy-chsy <wan.wenyan@xydigit.com>
2026-07-07 06:57:16 +01:00
Evgeni Obuchowski
72bd74e9dd fix(thinking): clamp below-range requests down to the cheapest level, not up (#93335)
resolveSupportedThinkingLevelFromProfile sorts the supported levels descending,
then, when every supported level exceeds the request (e.g. a stored `off` on a
profile that has no off level), fell through to `ranked.find(non-off)` — the
first entry of a descending list, i.e. the most expensive level. A session
carrying thinking `off` that switched onto such a model was silently remapped to
maximum reasoning and persisted (src/auto-reply/reply/directive-handling.persist.ts).

Use `ranked.findLast(non-off)` so a below-range request resolves to the cheapest
non-off level instead. Regression test included (red before, green after).

This surfaces with the first bundled no-off thinking profiles (Fireworks
GPT-OSS 120B, see #92217), but the clamp lives in shared core logic, so it ships
on its own.
2026-07-07 06:55:25 +01:00
袁焊忠
6ed2aafe3c fix(doctor): preview missing transcript cleanup (#83630)
* fix(doctor): preview missing transcript cleanup

* fix(doctor): preview missing transcript cleanup

---------

Co-authored-by: YuanHanzhong <YuanHanzhong@users.noreply.github.com>
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
2026-07-07 06:49:44 +01:00
Santiago
80bb0cd24e fix: include pnpm 11 bins in gateway PATH (#85238)
* fix: include pnpm 11 bins in gateway PATH

* fix: include pnpm 11 bins in gateway PATH

* fix(security): reject workspace package-manager PATH roots

* fix(infra): preserve package paths from root cwd

---------

Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-06 22:49:21 -07:00
dongdong
54be942e6b fix: avoid reminder-guard false positives for plain memory promises (#47586) (#93862)
* fix(auto-reply): narrow reminder guard remember matches

* test(auto-reply): prove reminder guard final payload

* fix(auto-reply): classify explicit reminder commitments

* fix(auto-reply): cover repeated reminder modals

* refactor(auto-reply): require explicit reminder actions

---------

Co-authored-by: Jasmine Zhang <jasminezhang@JasminedeMac-mini.local>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 06:29:29 +01:00
Peter Steinberger
3a482a71be fix(windows): remove findstr from restart probe (#101366)
* fix(windows): remove findstr from restart probe

Co-authored-by: Deepak Jain <deepujain@gmail.com>

* docs(changelog): note Windows restart probe fix

* docs(changelog): defer release note

---------

Co-authored-by: Deepak Jain <deepujain@gmail.com>
2026-07-07 06:29:13 +01:00
Qiong
7db7487a5d fix(security): route temp workspaces through private OpenClaw temp root (#101224) (#101246)
* fix(security): route temp workspaces through private OpenClaw temp root (#101224)

* test(infra): skip POSIX mode proof on Windows

* chore: align release changelog before main sync

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-07 06:25:35 +01:00
snowzlmbot
53580e13a4 fix(usage): preserve provider-billed zero totals (#101177)
* fix(usage): preserve provider-billed zero totals

* fix(usage): harden provider-billed cost provenance

* fix(openrouter): retry delayed generation metadata

* fix(openrouter): satisfy retry lint

* refactor(openrouter): consume streamed billed cost

* chore: keep release notes out of contributor PR

---------

Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 06:22:28 +01:00
Ashd.LW.
70c2e837cd fix(gateway): show last error when status probe fails (#95902)
* fix(gateway): show last error when status probe fails

* fix(gateway): scope status log diagnostics

---------

Co-authored-by: wAngByg <wAngByg@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-06 22:22:19 -07:00
Josh Lehman
5d9a2b114f feat(context-engine): report compaction successors as typed session targets (#101182) 2026-07-06 22:14:46 -07:00
Peter Lee
6192b037bb fix(tui): deduplicate assistant messages across sessions.changed reload (#96980)
* fix(tui): suppress adjacent history-replay/live-final duplicate in ChatLog (#96967)

When sessions.changed triggers loadHistory(), assistant rows are replayed
via finalizeAssistant(text) without a runId. A late live final with the
same text and a runId can land immediately afterward, producing a visible
duplicate assistant reply.

Track the most recent history-replay assistant component in ChatLog and
suppress a following live final when the text matches and no other
component was appended in between. This is simpler and more targeted
than the prior event-handler approach because it operates at the
rendering layer where the duplicate is actually visible.

Fixes #96967

* fix(tui): bound replay-final dedupe window in ChatLog

* fix(tui): bound replay-final dedupe marker with TTL expiration

* fix(tui): satisfy no-promise-executor-return lint rule in chat-log test

* fix(tui): replace ChatLog text heuristic with runId-based surrender tracking

Drop the lastHistoryAssistant text-matching dedupe in ChatLog
(posed P1 false-suppression risk). Instead, track active runIds
surrendered to loadHistory() on sessions.changed 'new' — late
events for surrendered runs are suppressed by exact runId match.

Add ChatLog.hasStreamingRun() so the event handler can detect
when loadHistory restored a surrendered run as in-flight streaming.

Retain chatFinalizedRuns / chatFinalizedRunsWithDisplay from the
original fix for post-reload delta/error dedup of finalized runs.

Incorporates the precise surrender-tracking approach from closed
PRs #96979/#96986 while keeping the scoped ChatLog API minimal.

* fix(tui): render displayable late final for surrendered non-streaming run

When a sessions.changed 'new' surrenders an in-flight run and
loadHistory does not restore it as streaming, a late displayable
final must still be rendered — otherwise the user never sees the
assistant reply. Only suppress non-displayable finals (empty
message, no errorMessage).

Add focused test for non-displayable final suppression.

* test(tui): add coverage for empty in-flight restore + late displayable final

Covers the rank-up scenario from #96979: surrendered run restored
by loadHistory as empty streaming, late displayable final passes
through surrender check and renders to chatLog.

* fix(tui): suppress late finals for surrendered finalized runs to prevent history-replay duplicate

When sessions.changed 'new' fires, now surrender chatFinalizedRuns entries
too (as 'finalized'), not just sessionRuns ('in-flight'). This prevents
the finalized-before-reload history-replay duplicate: a late final for an
already-displayed run gets suppressed because the history-replay static
row covers the visible content.

In-flight surrendered runs still render displayable finals because the
user may not have seen the streaming text before the reload.

SurrenderedToHistoryRunIds is now Map<string,'in-flight'|'finalized'>
so the surrender check can branch on source. Move surrender check before
the finalizedRuns/chatFinalizedRuns guard so surrendered finalized runs
are routed correctly.

Add focused tests for history-replayed-visible (suppress) and
history-replay-missing (render) late finals.

* fix(tui): extend surrender coverage to sessions.changed reset reload path

Reset also calls clearTrackedRunState() + loadHistory() with the same
sessionKey, so late chat events for runs from the old session window
can race with the history replay the same way as 'new'. Surrender
sessionRuns and chatFinalizedRuns on both reasons (#96979 P1 rank-up).

* fix(tui): keep surrendered finalized marker after late delta to block later final

For finalized surrendered runs, a late delta must not clear the
surrender marker — otherwise a subsequent late final would slip
through and produce a duplicate. Only in-flight surrendered runs
clear the marker on delta (their final needs to render).

* fix(tui): gate session history reloads on persistence

Co-authored-by: xialonglee <li.xialong@xydigit.com>

* docs(changelog): note TUI external-run dedupe

* test(tui): type history load harness results

* test(tui): defer history results without async mocks

* chore(changelog): defer TUI note to release

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 06:06:53 +01:00
Wynne668
78e4672d65 fix: pace delivery recovery after startup outages (#101118)
* fix: pace delivery recovery replays

* fix: preserve paced delivery recovery budget

* fix(delivery): preserve recovery deadline while pacing

* fix(delivery): coordinate recovery replay pacing

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 05:58:12 +01:00
Vincent Koc
bbd01c169e test(update): seed extended-stable install preflight 2026-07-07 06:35:44 +02:00
Vincent Koc
84e5327720 fix(text): keep bounded outputs UTF-16 safe (#101355)
Co-authored-by: Alix-007 <li.long15@xydigit.com>
2026-07-06 21:33:24 -07:00
cxbAsDev
325cdb7f1a fix(infra): swallow mid-stream read errors in session-cost readJsonlRecords (#101062)
* fix(infra): swallow mid-stream read errors in session-cost readJsonlRecords

* fix(infra): keep usage cache strict on read errors

---------

Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-06 21:23:30 -07:00
Buddy Hadry
964fd53076 fix(update): keep self-updates on the running install's global root (#101228)
* fix(update): keep self-updates on the running install's global root

Package self-updates resolved their install target from `npm root -g`
even when the running install's package root was already known. In an
environment where PATH's npm does not belong to the running install's
Node tree (a launchd/systemd service PATH, or mixed Homebrew + nvm
setups), the probe points at a different global root — or derives a
brand-new one — so the update installs there, reports success, and
leaves the running install stale.

Observed in the wild: a gateway-managed `openclaw update --yes` on
2026.5.28 ran nvm's npm under Homebrew's node, npm derived its default
prefix from the realpathed execPath, and the update installed a full
copy into /opt/homebrew/Cellar/node/26.3.1/lib/node_modules/openclaw
("before": null — a tree that had never existed) while the running nvm
install stayed on the old version until a manual shell update.

resolveGlobalInstallTarget now prefers the package root's own global
root for npm targets; the `npm root -g` probe only decides the target
when no package root is known, and an ephemeral per-Node probe result
(Homebrew Cellar, nvm/n/asdf/volta version dirs — the same set
#93650 filters npm commands against) is never adopted.

* fix(update): infer global roots for scoped package roots

The running-root fallback missed scoped installs because
inferGlobalRootFromPackageRoot only accepted an immediate node_modules
parent. Hop over an @scope segment so node_modules/@scope/name resolves
to the same global root. Regression test: scoped package root with an
ephemeral probe now falls back to the running root.

* fix(update): scope running-root selection

* docs(changelog): note npm self-update root fix

* chore(changelog): defer release note

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 05:21:14 +01:00
Jason (Json)
9b2bb9c0a6 fix(models): refresh provider auth after CLI login (#101256)
* fix(models): refresh gateway auth after login

* docs(changelog): note model auth live refresh

* chore(changelog): defer release note

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 05:20:35 +01:00
Marcus Castro
31432bf101 fix(reply): preserve steered audio for inbound TTS (#95596)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 05:18:36 +01:00
Peter Steinberger
7a5e5e1852 fix(codex): register the ring-zero crestodian tool directly instead of relying on a dead per-run plugin config override (#101281) 2026-07-07 05:08:08 +01:00
Ayaan Zaidi
dc5d4138f9 test(gateway): isolate reload handler plugin records
The reload handler no-op config test enables fake timers and drains all timers. In cross-file non-isolated runs, server-startup-post-attach closes the shared state DB first, so this test reopens it through the managed config reloader's default installed-plugin record read.

That DB open schedules SQLite WAL maintenance at src/infra/sqlite-wal.ts:345 while fake timers are active, and vi.runAllTimersAsync spins the interval until Vitest aborts after 10000 timers. Mock installed plugin record reads in this handler test so the test owns only the reload debounce timer it is trying to drain.
2026-07-06 20:52:42 -07:00
Yuval Dinodia
7900ff4731 fix(macos): preserve device identity storage (#101105)
* fix(macos): preserve device identity storage

Avoid selecting App Group identity storage when the running app lacks the matching application-groups entitlement, so unentitled macOS builds fall back to the legacy writable identity directory. Existing unrecognized identity files are now preserved instead of being replaced by a newly generated identity, matching the no-overwrite behavior already used for recognized invalid identity data.

* fix(macos): repair identity CI coverage

Limit the App Group entitlement probe to macOS builds so iOS keeps its existing App Group path behavior. Update the state-dir identity regression to assert the new no-overwrite contract for invalid identity-shaped files.

* fix(macos): migrate existing app group identity on legacy fallback

Unentitled macOS builds now migrate a readable App Group device identity
into the selected legacy store before falling back, so an upgrade preserves
the existing device id instead of minting a new one.

* fix(macos): migrate device auth store with identity on app group fallback

The app group to legacy identity migration now carries the sibling
device-auth store file, so an unentitled build keeps its stored device
tokens (keyed by the migrated deviceId) instead of re-pairing. The
process-immutable entitlement check is resolved once per process rather
than creating a SecTask on every state-dir lookup, and the migration
source API returns an identity+auth pair struct.

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 04:49:46 +01:00
Jesse Merhi
4112e3a0f3 Add native Signal reply quotes (#95718)
* feat(signal): quote native replies

* Fix Signal native reply edge cases

* fix(signal): tighten native reply quotes

* fix(signal): harden native reply quotes

* fix(signal): preserve approval reaction state

* fix(signal): target native replies to edited messages

* fix(signal): preserve plugin approval reaction kind

* fix(signal): keep edit event reply ids distinct
2026-07-07 13:49:13 +10:00
Peter Steinberger
1834592be1 fix(auth): use OpenClaw lobster logo on OAuth callback pages
The shared provider OAuth success/error page (OpenAI/Codex and Anthropic
login flows) still embedded the legacy Pi logo SVG. Swap it for the
OpenClaw lobster mascot, matching ui/public/favicon.svg.
2026-07-07 04:48:01 +01:00
Vincent Koc
0fd69dc3d2 fix(wizard): honor configured auth dir in finalize 2026-07-07 05:41:02 +02:00
Ayaan Zaidi
c718afe247 refactor(agents): thread runtime-context carrier indexes 2026-07-06 20:34:01 -07:00
Peter Lindsey
f5931f5516 fix(agents): carry current-turn inbound metadata in a tail runtime-context message for byte-stable prompt caching
The active user turn was decorated at request-build time with an inbound
metadata block (Conversation info / reply-target / sender / forwarded /
chat-history), but the session store persists the bare text and the LLM boundary
strips that block from historical replay. So a user message's serialized bytes
changed retroactively — decorated as the active turn, bare as history — on every
turn, invalidating any prefix/exact-match provider prompt cache from that point
onward, every turn. (#90811 fixed the timestamp half of this same asymmetry.)

Rework of the earlier "strip the active turn" approach (which lost model-visible
context — ClawSweeper's P1) into one that keeps the context AND recovers the
cache cost:

- Route current-turn inbound metadata out of the user prompt and into the hidden
  runtime-context custom message (the mechanism from openclaw#89428), and
  relocate that carrier to the ABSOLUTE TAIL of the wire request (after the
  active user turn and any tool-call scaffolding). The user turn stays bare and
  byte-identical in both the active and historical positions; the volatile
  carrier vanishes next turn exactly where the assistant reply begins anyway, so
  the request is an append-only prefix-extension through the active user turn.
- A durable marker (UserMessage.runtimeContextCarrier, set by convertToLlm from
  the carrier's details) lets the Anthropic SDK transport, the managed Anthropic
  transport (anthropic-transport-stream / anthropic-payload-policy), and
  OpenAI-completions skip the carrier when selecting the deepest cache_control
  breakpoint, keeping the anchor on the last stable user turn.

Storage stays BARE (invariant preserved); runtime-only turns (room events) keep
their existing inline behavior, which is byte-stable because room-event/system
context is not strip-eligible; legacy bare-stored sessions are unchanged.

Reviewed with adversarial gpt-5.5/codex sweeps (correctness, byte-identity,
compatibility, test adequacy): found + fixed the managed Anthropic transport
cache-anchor path and added the missing OpenAI-completions/managed-transport
breakpoint tests; a theoretical runtime-only mutation was verified unreachable
and pinned with a test. Final sweep clean.

Co-authored-by: openclaw#89428 (runtime-context handoff approach)
2026-07-06 20:34:01 -07:00
Ayaan Zaidi
f7df9536b0 docs(agents): note codex session-id header naming divergence 2026-07-06 20:33:51 -07:00
Peter Lindsey
06061c4fe3 fix(agents): treat caller session_id headers as case-insensitive
buildOpenAIClientHeaders only skipped generating a session_id header
when the exact lowercase key was already present, so a caller-supplied
Session_ID or SESSION_ID header would end up on the wire alongside our
generated one instead of winning per the caller-wins header contract.
Check all resolved header keys case-insensitively before injecting.
2026-07-06 20:33:51 -07:00
Peter Lindsey
3d87932541 fix(agents): send session_id affinity header to ChatGPT Responses backend
The ChatGPT backend routes requests by session_id (codex-cli sends it); without it each request lands on an arbitrary machine and the prompt cache misses. Measured on live traffic: 56.0% -> 81.8% TRUE cache hit rate (12-turn A/B, identical prompts).
2026-07-06 20:33:51 -07:00