Summary:
- Adds a Vitest regression case in `src/agents/session-file-repair.test.ts` for `repairSessionFileIfNeeded` preserving a final stop assistant message after a tool-call/tool-result pair.
- Reproducibility: yes. The added JSONL sequence can be traced through current `repairSessionFileIfNeeded`: no ... ry, so the function returns `repaired: false`; I did not execute the test because this review is read-only.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head ee3aa0e036.
- Required merge gates passed before the squash merge.
Prepared head SHA: ee3aa0e036
Review: https://github.com/openclaw/openclaw/pull/76538#issuecomment-4365670008
Co-authored-by: Vinh Nguyen <vinhnt36@fpt.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixes#76176.
OpenAI live verification showed `gpt-5.4-mini` supports reasoning effort generally, but rejects `/v1/chat/completions` payloads that combine function tools with `reasoning_effort`. This keeps reasoning effort for tool-free Chat Completions and Responses, and omits it only for the rejected Chat Completions + function tools combination.
Validation:
- Live OpenAI API matrix on 2026-05-03
- pnpm test src/agents/openai-reasoning-effort.test.ts src/agents/openai-transport-stream.test.ts -- --reporter=verbose
- GitHub PR CI green on ea3915308c
Thanks @ThisIsAdilah and @chinar-amrutkar.
Fixes the session-list plugin metadata hot path by reusing the active workspace-scoped plugin metadata snapshot for manifest model-id normalization and setup CLI backend fallback. Also keeps model-pricing collection on its provided manifest registry and fixes the CI-only hoisted test mock failure.
Validated with targeted plugin/gateway/model-selection tests, CI-shaped gateway startup shard, Testbox `pnpm check:changed`, and green PR CI.
Thanks @rolandrscheel.
- gate the compaction continuation retry on existing replay side-effect metadata
- type the bundled compaction notifier hook without explicit any
- add an Unreleased changelog entry
When an automatic compaction happens mid-turn, chat users currently see a long stall and the run can finish without a final visible answer.
This adds an optional bundled compaction notifier hook and a one-shot compacted-transcript continuation retry when a compaction produced no user-visible final payload.
Summary:
- The branch marks runtime `toolsAllow` sources as enforceable during disabled-tool runs, filters inherited allowlist sources in the guard, adds focused guard coverage, and updates the changelog.
- Reproducibility: yes. The linked report gives concrete config and invocation steps, and source inspection on ... sables tools while the guard still treats inherited allowlist sources plus zero callable tools as an error.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 9c3e5f773e.
- Required merge gates passed before the squash merge.
Prepared head SHA: 9c3e5f773e
Review: https://github.com/openclaw/openclaw/pull/76686#issuecomment-4366216196
Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
Summary:
- The PR changes the agent web_search wrapper to keep runtime provider discovery enabled when runtime metadata is absent, adds focused regression coverage, and records an unreleased changelog fix.
- Reproducibility: yes. at source level: current main passes preferRuntimeProviders: false when runtime web-se ... d issue supplies live Brave CLI-vs-agent evidence; this read-only review did not rerun a live Gateway call.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head e7f379c68d.
- Required merge gates passed before the squash merge.
Prepared head SHA: e7f379c68d
Review: https://github.com/openclaw/openclaw/pull/76685#issuecomment-4366216450
Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
The sandbox registry stores one JSON document per scope (containers
and browsers), with every writer serialized through
`acquireSessionWriteLock` against that single file. In a host running
several sessions in parallel — multiple pairings, subagent spawns, or
just an `ensureSandboxContainer` landing at the same moment as a
`removeRegistryEntry` — each writer waits up to 60s for the lock, and
a crashed process can leave the lock file behind long enough to
wedge every subsequent sandbox operation until the stale-lock
threshold elapses. The lock's only job is to keep entries from
trampling each other inside one JSON blob, so it is a whole-file
mutex gating reads/writes that touch disjoint entries.
Each container already has a unique name (enforced at creation), so
each entry's storage can be disjoint too. This change turns the
`~/.openclaw/sandbox/containers.json` and `browsers.json`
monolithic files into per-entry JSON files under
`~/.openclaw/sandbox/containers/` and `~/.openclaw/sandbox/browsers/`
directories. `writeJsonAtomic` (tmp-file + rename) keeps each
per-entry write crash-safe, and because concurrent writers only
touch their own files there is nothing left to serialize across.
Changes:
- `src/agents/sandbox/constants.ts`: add `SANDBOX_CONTAINERS_DIR`
and `SANDBOX_BROWSERS_DIR` sibling to the existing monolithic
paths. The old paths stay exported because the one-shot migration
still needs to locate the legacy file.
- `src/agents/sandbox/registry.ts`: replace the
`withRegistryLock` / `readRegistryFromFile("strict")` /
`writeRegistryFile` loop with per-entry read/write/remove
primitives against the sharded directories, and drop the
`acquireSessionWriteLock` import. The existing upstream additions
are preserved: the zod `RegistryEntrySchema`, the
`backendId`/`runtimeLabel`/`configLabelKind` fields on
`SandboxRegistryEntry`, and `normalizeSandboxRegistryEntry` still
decorate reads. Upsert merge semantics (preserve `createdAtMs` and
`image` from the prior entry, prefer the newer `configHash`) are
kept bit-for-bit.
- `src/agents/sandbox/registry.ts`: add `readRegistryEntry(name)`
for O(1) single-container lookup. The previous hot path in
`ensureSandboxContainer` had to read the whole registry and
`Array.find` the one entry it wanted; the new API avoids both the
full directory scan and the JSON round-trip on every other entry.
- `src/agents/sandbox/registry.ts`: add a one-shot
`migrateMonolithicIfNeeded` helper invoked at the top of every
public read/write. If a legacy `containers.json` / `browsers.json`
exists, its entries are fanned out into per-entry files, the old
file and its `.lock` are removed, and subsequent calls skip the
migration branch entirely. Malformed legacy files are dropped
rather than throwing forever, because a corrupt single-file
registry that has already been superseded by the new storage
would otherwise block every sandbox ensure/remove on every boot.
Live per-entry files still go through the same schema validation
the upstream strict path used — a corrupt per-entry file is
simply skipped during enumeration so that one bad file cannot
hide every other running container from the operator.
- `src/agents/sandbox/docker.ts`: swap the `readRegistry()` +
`Array.find` lookup in `ensureSandboxContainer` for the new
`readRegistryEntry(containerName)`. This is the only in-tree
caller that needed the full scan just to pick one entry.
- `src/agents/sandbox/registry.test.ts`: rewrite around the new
per-file semantics. The old tests covered two properties that no
longer exist — "the lock serializes concurrent update/remove so
the later write cannot resurrect a removed entry" and "a
malformed monolithic file makes every `update` throw" — both of
which were artifacts of the single-file design. The rewrite keeps
the normalizeSandboxRegistryEntry contract, the
concurrent-updates-succeed contract (now without any lock in
play), the malformed-legacy-migration contract, and adds coverage
for `readRegistryEntry`, the stale-`.lock` cleanup, and the
"corrupt per-entry file does not hide its siblings" guarantee.
- `src/agents/sandbox/docker.config-hash-recreate.test.ts`: update
the mock module to expose `readRegistryEntry` instead of
`readRegistry`, and return single-entry objects or `null` rather
than `{ entries: [...] }`.
Other in-tree consumers (`manage.ts`, `prune.ts`, `browser.ts`,
`context.ts`) only call the public `readRegistry` / `updateRegistry`
/ `remove*` surface, whose return shapes and observable behavior
are unchanged; their existing tests (`manage.test.ts`,
`browser.create.test.ts`, `sandbox.resolveSandboxContext.test.ts`)
all pass unmodified.
Default behavior is unchanged from the operator's point of view:
the first boot on the new code sees the legacy files, migrates them
in place, and deletes them. Subsequent boots never touch the
migration path. No config surface, no types, and no public exports
are removed.
* fix(agents): detect incomplete tool-use turns with pre-tool text (#76477)
When the last assistant message ended with stopReason=toolUse, pre-tool
text alone (payloadCount > 0) was suppressing the incomplete-turn guard.
The model expected to continue after tool results but the post-tool
response was never produced, silently dropping the final answer.
Fix isIncompleteTerminalAssistantTurn to always flag toolUse stop reason
as incomplete regardless of pre-tool text, and update the early-return
condition in resolveIncompleteTurnPayloadText to not skip the check when
the last assistant ended with a tool call.
* fix(agents): mark tool-use terminal with pre-tool text as abandoned in lifecycle (#76477)
The lifecycle handler's derivedWorkingTerminalState was emitting
'working' for interrupted tool-use turns with pre-tool text because
it required !hasAssistantVisibleText for the 'abandoned' state.
Update the derivation to also mark as 'abandoned' when
incompleteTerminalAssistant is true, so lifecycle consumers see a
consistent state with the runner's terminal result.
Summary:
- The PR makes `tools.profile: "full"` resolve to a wildcard allowlist, teaches plugin optional-tool allowlist checks to honor `*`, and updates regression tests, docs, and the changelog for browser tool availability.
- Reproducibility: yes. source-level reproduction is high confidence: current main makes `full` resolve to no ... plugin allowlist helpers do not accept `*`. I did not run a live browser session in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: docs: update full profile description and add changelog for #76507
Validation:
- ClawSweeper review passed for head b5329de33c.
- Required merge gates passed before the squash merge.
Prepared head SHA: b5329de33c
Review: https://github.com/openclaw/openclaw/pull/76557#issuecomment-4365736091
Co-authored-by: Alex Knight <aknight@atlassian.com>
* fix(gateway): read-only fast path for models.list catalog loading
The gateway model catalog refresh calls loadModelCatalog without
readOnly, triggering ensureOpenClawModelsJson (60-70s), full PI SDK
registry instantiation, auth storage discovery, and live provider
plugin augmentation on every Control UI list/refresh. None of this
is needed for a read-only UI listing.
Three changes:
1. Gateway catalog refresh now passes readOnly: true to loadModelCatalog.
2. In readOnly mode, skip augmentModelCatalogWithProviderPlugins — live
provider discovery is explicit admin/background work, not a UI list
operation.
3. Add a persisted models.json fast path: when readOnly is true, first
try reading the existing models.json directly and converting
providers.<provider>.models[] to catalog rows. Falls back to the
full PI registry path if the file is missing or unreadable.
Observed improvement on a production install:
loadGatewayModelCatalog: 967 entries / 4651ms → 89 entries / 8ms
Live models.list during startup: ~18s → ~2s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(gateway): preserve full model catalog view
* fix(agents): preserve read-only catalog defaults
* fix(agents): preserve provider catalog defaults
---------
Co-authored-by: Marvinthebored <peter@lindsey.jp>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Summary:
- The PR removes session-file repair's trailing-assistant disk trim, updates regression coverage, clarifies transcript hygiene docs, and adds a changelog entry for the Telegram/WebChat history loss fix.
- Reproducibility: yes. Current main has a clear source path: a normal trailing assistant JSONL record is popped by `repairSessionFileIfNeeded`, and the main-branch test suite asserts that deletion.
Automerge notes:
- PR branch already contained follow-up commit before automerge: docs(agents): clarify session repair preservation
- PR branch already contained follow-up commit before automerge: fix(agents): preserve delivered assistant replies in session repair
Validation:
- ClawSweeper review passed for head 66c187fd76.
- Required merge gates passed before the squash merge.
Prepared head SHA: 66c187fd76
Review: https://github.com/openclaw/openclaw/pull/76420#issuecomment-4365323320
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Summary:
- The PR threads the embedded run's trusted requester agent id into plugin tool context and memory-core tool availability/execution, adds regression tests, and records an Active Memory changelog fix.
- Reproducibility: yes. Current main shows Active Memory passing a synthetic `:active-memory:` session key plu ... ently derive memory scope from the session key; I did not run the regression test in this read-only review.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 33ab3d7fc7.
- Required merge gates passed before the squash merge.
Prepared head SHA: 33ab3d7fc7
Review: https://github.com/openclaw/openclaw/pull/76380#issuecomment-4365186657
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
Summary:
- The PR skips eager context-window warmup for `openclaw message`, forwards Discord/Telegram execution-mode de ... reuses caller-owned manifest metadata during config materialization, and adds tests plus a changelog entry.
- Reproducibility: yes. Source inspection on current main shows `openclaw message` is still eligible for eager context-window warmup and the Discord/Telegram wrappers still drop the gateway execution-mode declarations.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix: type message action routing fallbacks
- PR branch already contained follow-up commit before automerge: docs: credit message latency fix contributor
Validation:
- ClawSweeper review passed for head 9606bb27d5.
- Required merge gates passed before the squash merge.
Prepared head SHA: 9606bb27d5
Review: https://github.com/openclaw/openclaw/pull/76312#issuecomment-4364958708
Co-authored-by: FullerStackDev <263060202+fuller-stack-dev@users.noreply.github.com>
Fix the Windows stale-import guard regex used by the Parallels npm update smoke path, with related maintainer-flow and regression-test cleanup preserved on a verified branch.
Reduce WebUI/Gateway latency churn by avoiding redundant session reloads, carrying session keys through transcript update events, and deferring explicit media provider discovery. Includes changelog attribution and closes the referenced runtime latency issues.
Summary:
- The branch removes the compact image/video provider-inventory output bypass, adds media handler regression tests for hidden and verbose modes, and adds an Unreleased changelog fix entry.
- Reproducibility: yes. On current main, a synthetic image_generate or video_generate list result with details ... ut false reaches emitToolOutput; the existing media handler test locks in that old video_generate behavior.
ClawSweeper fixups:
- Included follow-up commit: chore: rerun ci
- Included follow-up commit: chore: move changelog entry below media fixes
Validation:
- ClawSweeper review passed for head 56069df903.
- Required merge gates passed before the squash merge.
Prepared head SHA: 56069df903
Review: https://github.com/openclaw/openclaw/pull/75550#issuecomment-4358608888
Co-authored-by: mkdev11 <MkDev11@users.noreply.github.com>
Summary:
- The branch reuses a request-scoped subagent registry read index across Gateway `sessions.list` `spawnedBy` filtering and row enrichment, with focused regression tests and a changelog entry.
- Reproducibility: yes. On current main, `spawnedBy` filtering still calls registry read helpers independently ... ce inspection gives a high-confidence reproduction path for snapshot drift during active registry mutation.
ClawSweeper fixups:
- Included follow-up commit: fix(gateway): reuse subagent registry snapshot in session listing
Validation:
- ClawSweeper review passed for head 23ae624374.
- Required merge gates passed before the squash merge.
Prepared head SHA: 23ae624374
Review: https://github.com/openclaw/openclaw/pull/75019#issuecomment-4351613760
Co-authored-by: anyech <anyech@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>