Files
openclaw/ui
Peter Steinberger a3283af7c7 feat(ui): complete the Labs roster with the remaining experimental gates (#114233)
* feat(ui): complete the Labs roster with the remaining experimental gates

Labs shipped with two entries while three more experimental surfaces stayed
reachable only by hand-editing config. Adds Tool Search, lean local-model tools,
and message audit metadata, each with the subtext and documentation link the
page already promises.

Two of them do not fit the boolean gate the registry assumed, so the registry
now states each row's on/off values instead of hardcoding true/false:

- Tool Search is a mode, and resolveToolSearchConfig defaults an unset mode to
  "code" even in object form. A bare enable would therefore select the surface
  with the weakest recall rather than the bounded directory this row advertises,
  so enabling writes `mode: "directory"` alongside the gate in one patch.
- Message audit is `off | direct | all`. Labs offers the conservative `direct`,
  so turning it on cannot start recording group or unknown conversations the
  operator never opted into, and `all` deliberately does not read as on — that
  is a broader choice made elsewhere and this row must not quietly narrow it.

The audit row carries a restart hint because startGatewayEventSubscriptions
resolves the mode once and bakes it into the recorder, which outlives the reload
plan's `logging: none` rule. The other four are read per agent run.

* fix(ui): read a broader audit mode as enabled instead of narrowing it

`all` records more than the `direct` this row offers, but it is still on. Strict
equality against onValue rendered it as off, which made the switch look available
and would have silently rewritten a deliberately broader operator setting down to
`direct` on the next click.

Separate "what enabling writes" from "what counts as enabled": onValue stays the
value Labs sets, activeValues lists every value that reads as on. Turning the row
off from `all` now writes `off`, which is the only narrowing the operator asked
for.

The test that covered this asserted the opposite of what its own comment
described; corrected, plus coverage for the off-from-all write.

* fix(ui): mirror the runtime rule for Tool Search enablement

ToolSearchConfig is a union, and resolveToolSearchConfig treats an object that
configures anything besides `enabled` as already on:
`readBoolean(raw.enabled, configured)`. Reading only the `enabled` leaf showed
`{ mode: "tools" }` as off, so the row offered a switch that would have replaced
that operator's mode with `directory` — the same narrowing the audit row was
just fixed for.

Give the registry a `readEnabled` override for gates whose enablement is not a
single leaf, and point Tool Search at a copy of the runtime rule with the
resolver named so the two stay comparable. The other four rows keep the leaf
read and declare `readEnabled: null` explicitly.

* chore(ui): keep LabFeatureValue local to the registry

Only the registry names the type, and the hard-zero Knip production scan rejects
an export with no production consumer outside its own module.
2026-07-26 22:11:14 -04:00
..