Commit Graph

40516 Commits

Author SHA1 Message Date
Peter Steinberger
fd5e6ae9f1 chore: remove stale root tooling files 2026-05-03 13:29:34 +01:00
Peter Steinberger
a7b76835d4 ci: ignore generated extension viewer asset in lint 2026-05-03 13:28:30 +01:00
Peter Steinberger
ca69917153 test(sandbox): cover registry migration 2026-05-03 13:25:32 +01:00
Peter Steinberger
1402997489 fix(sandbox): move registry file migration to doctor 2026-05-03 13:25:32 +01:00
Peter Steinberger
1cebe32d76 fix(sandbox): harden sharded registry storage 2026-05-03 13:25:32 +01:00
Vincent Koc
164dfc4218 fix(sandbox): remove registry helper generics 2026-05-03 13:25:32 +01:00
hobo
975891153f perf(sandbox): shard container registry into per-entry files to remove cross-session lock contention
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.
2026-05-03 13:25:32 +01:00
HCL
deb7b821c1 fix(plugins): include selected context-engine slot plugin in gateway startup (#76576)
External context-engine plugins (e.g. lossless-claw) register via
api.registerContextEngine at load time but ship without
activation.onStartup in their manifest. The gateway startup planner
only considered memory plugins and explicit sidecar plugins, so a
selected non-legacy context engine was omitted from the startup load
plan and never loaded before agent turns resolved the active engine,
producing the "Context engine X is not registered; falling back to
default engine legacy" warning.

Fix: add resolveContextEngineSlotStartupPluginId mirroring the memory
slot pattern; pass contextEngineSlotStartupPluginId into
shouldConsiderForGatewayStartup so the selected context-engine plugin
is included in pluginIds regardless of its manifest activation shape.

Tests: added four regression cases covering include, exclude, legacy
bypass, and id normalization. 82 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 13:22:47 +01:00
Peter Steinberger
d00bcf555b test(plugins): cover config-origin tool cold load diagnostics 2026-05-03 13:22:47 +01:00
HCL
a3b94f3910 fix(plugins): restore cold-registry load for path-based plugin tools (#76598)
`resolvePluginTools` returned an empty tool list when no pre-warmed
channel/active registry was found after startup — the on-demand fallback
removed by PR #76004 was only added back for memory and capability-provider
surfaces, leaving path-based (origin "config") plugin tool factories silent.

Fix: when `resolvePluginToolRegistry` returns null, trigger a standalone
registry load via `ensureStandaloneRuntimePluginRegistryLoaded`, then retry.
Adds regression test asserting tools are resolved without pre-warming.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 13:22:47 +01:00
Conan-Scott
8ebf86cdff fix(plugins): preserve external capability provider fallback (#76536)
* fix(plugins): preserve external capability provider fallback

* docs: move changelog entry to avoid merge conflict

---------

Co-authored-by: Clawdbot <clawdbot@apilab.us>
2026-05-03 13:22:34 +01:00
Peter Steinberger
4fff25438c fix: propagate stream timeout abort reason (#76633) 2026-05-03 13:21:02 +01:00
mkdev11
ffd3dfa4f5 fix agents stream timeout heartbeat 2026-05-03 13:21:02 +01:00
Peter Steinberger
4760ee4055 chore: remove root assets 2026-05-03 13:20:26 +01:00
Peter Steinberger
2b82c05a7f fix(plugins): include inherited tts persona providers at startup 2026-05-03 13:17:24 +01:00
Peter Steinberger
4bc82fc787 docs: note config dry-run schema validation fix 2026-05-03 13:17:13 +01:00
Peter Steinberger
81fea91fda fix: restore config dry-run schema validation 2026-05-03 13:16:20 +01:00
Peter Steinberger
9a49d143c8 test: update config patch schema fixture 2026-05-03 13:16:10 +01:00
Peter Steinberger
0f66ad4243 ci: pin fixed Kova benchmark 2026-05-03 13:12:31 +01:00
Peter Steinberger
6e2f394473 test(auto-reply): guard message-tool-only reply privacy 2026-05-03 13:12:26 +01:00
Peter Steinberger
869103684f chore: move swabble into apps 2026-05-03 13:10:25 +01:00
Peter Steinberger
0031ef3120 refactor: keep legacy secretref migration in doctor 2026-05-03 13:10:00 +01:00
Peter Steinberger
e0a83c0046 test: fix tui command completion typecheck 2026-05-03 13:03:11 +01:00
Peter Steinberger
45a5374ca8 perf: reduce raw gateway config startup work 2026-05-03 13:03:11 +01:00
Peter Steinberger
73be4ea901 ci: fix full release validation gates 2026-05-03 13:01:14 +01:00
Peter Steinberger
0fbb06e6df ci: use org-owned Kova benchmark 2026-05-03 12:57:39 +01:00
Peter Steinberger
adc4fd453b chore: move test tsconfigs 2026-05-03 12:56:52 +01:00
byungskers
f7522edb96 fix(plugins): preserve sibling npm installs
Run npm install from the managed npm-root manifest so sequential @openclaw/* plugin installs preserve siblings on disk.

Fixes #76571.
Thanks @byungskers and @crpol.
2026-05-03 12:51:50 +01:00
Peter Steinberger
b8a4d6a58a test: move root contract fixture 2026-05-03 12:48:16 +01:00
Chunyue Wang
c1b9af2770 fix(ollama): restore catalog-driven num_ctx for native /api/chat (#76181)
Merged via squash.

Prepared head SHA: d3142252d5
Co-authored-by: openperf <80630709+openperf@users.noreply.github.com>
Co-authored-by: openperf <80630709+openperf@users.noreply.github.com>
Reviewed-by: @openperf
2026-05-03 19:47:36 +08:00
Peter Steinberger
1507c6dac7 perf: reduce gateway startup overhead 2026-05-03 12:44:23 +01:00
Alex Knight
8142e67d63 fix(plugins): start configured speech providers (#76540)
* fix(plugins): start configured speech providers

* fix(plugins): mirror tts provider selection
2026-05-03 21:41:50 +10:00
Alex Knight
d0dc72bf32 test: harden flaky CI assertions (#76624) 2026-05-03 21:41:47 +10:00
volcano303
1d657b9d5f fix(active-memory): preserve setup grace for embedded recall
Apply setupGraceTimeoutMs to the embedded recall runner as well as the outer Active Memory watchdog.

Co-authored-by: volcano303 <75143900+volcano303@users.noreply.github.com>
2026-05-03 12:41:19 +01:00
Alex Knight
8a0e3b6422 test(ui): clean up navigation teardown (#76625) 2026-05-03 21:41:08 +10:00
Peter Steinberger
5ab4e6f9d9 chore: clean up editor metadata 2026-05-03 12:39:15 +01:00
Alex Knight
54a81e0080 fix: expose session-specific thinking levels (#76548)
* fix: expose session-specific thinking levels (#76482)

* fix: preserve lightweight sessions.list contract, fix consumer-side fallbacks only

* fix: include thinking levels in lightweight session rows for Control UI (#76482)

The Control UI cannot resolve provider-specific thinking levels client-side
(ui/src/ui/thinking.ts always returns base 5 levels). The gateway must
provide them even in lightweight rows. listThinkingLevelOptions is a cheap
in-memory lookup — negligible perf impact vs the transcript/cost/model ops
that the lightweight flag still skips.

Also update existing test assertions that expected thinkingOptions: [] for
lightweight rows (flagged by ClawSweeper review).

* test: add e2e regression tests for thinking level pipeline (#76482)
2026-05-03 21:38:32 +10:00
Alex Knight
a92e2b13b8 fix(agents): detect incomplete tool-use turns with pre-tool text (#76477) (#76544)
* 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.
2026-05-03 21:32:06 +10:00
Peter Steinberger
79f77d877e docs: move incident response plan 2026-05-03 12:30:11 +01:00
Peter Steinberger
f273083378 fix(doctor): match stale plugin records exactly 2026-05-03 12:26:42 +01:00
Peter Steinberger
1584acb124 fix(secrets): stabilize credential matrix docs 2026-05-03 12:25:08 +01:00
Peter Steinberger
c850d1bb0d fix(qqbot): harden clientSecret SecretRefs 2026-05-03 12:25:08 +01:00
xialonglee
40f970a13d feat(qqbot): resolve clientSecret SecretRefs and add secret contract 2026-05-03 12:25:08 +01:00
Ray
153e4c59cf docs(active-memory): document setup grace cold starts
Docs-only follow-up for setupGraceTimeoutMs and first-recall cold-start troubleshooting.\n\nThanks @RayWoo.
2026-05-03 12:24:35 +01:00
Peter Steinberger
5f4fd05074 ci: speed up full release validation 2026-05-03 12:24:24 +01:00
Peter Steinberger
5e9135f2e2 fix: keep active memory tools available 2026-05-03 12:24:03 +01:00
Peter Steinberger
02c2160478 chore: clean up root clutter 2026-05-03 12:20:52 +01:00
Peter Steinberger
4ec1efbcbc fix(catalog): pin prerelease channel npm specs 2026-05-03 12:18:56 +01:00
Peter Steinberger
8dd6a2d323 fix(channels): preserve degraded voice text and mention boundaries 2026-05-03 12:17:11 +01:00
Alex Knight
1e4098134a fix: enable browser tools with full profile (#76557)
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>
2026-05-03 11:12:30 +00:00