* feat: add session thread management
Squash of codex/thread-management (025aefc3ad1) onto origin/main:
pin/archive/rename sessions via sessions.patch, archived-aware
sessions.list, lifecycle fencing, read-only archived chat, SDK +
Swift protocol support, Control UI session management.
* refactor(ui): minimal session rows with hover-revealed management
Chat picker and sidebar recents share session-row primitives: single-line
rows, relative timestamps, rename/archive/pin revealed on hover or focus,
accent pin badge for pinned rows, and an active-run spinner in the trail
slot. Sidebar floats pinned sessions above recency via the shared
comparator and gains archive/pin actions through the unified sessions-view
patch fallback. Archive eligibility is one shared policy
(canArchiveSessionRow); the sidebar/picker active-run tooltip now uses the
real sessionsView.activeRun locale key.
* fix: align session admission with mailbox-era main
Integration fixes after rebasing onto current main: sessions_list mailbox
test expectations learn the archived/pinned row fields and archived:false
list param; gateway agent admission treats a session as deleted only when
both the requested and canonical alias sets miss it (legacy bare-main
stores and exec-approval followups read under different spellings); cron
persist tests keep a consistent store across claim-guarded persist calls;
the ACP abort hook test asserts abort propagation instead of signal
identity; drop dead lifecycle writes flagged by no-useless-assignment and
fix the promise-executor return in the codex compact test.
* fix(qa): align UI e2e and shard fixtures with redesigned session rows
Sidebar session rows are wrapper divs with an inner link now: update the
navigation browser tests and chat-flow Playwright selectors. Seed a real
per-test session store for the auto-fallback admission guard instead of
depending on leftover host files at /tmp/sessions.json. Teach the
test-projects routing fixture about the suites that newly import the
shared temp-dir helper. Document the Codex thread-format contract for
archivedAt/pinnedAt (flag derived from server-stamped timestamp, epoch ms
here vs Codex epoch seconds) at the type and in the session docs.
* test: route auto-fallback suite through temp-dir helper plans
The auto-fallback suite now imports the shared temp-dir helper for its
seeded session store, so the top-level helper routing fixture must list
it in the auto-reply plan.
* feat(gateway): add device.pair.setupCode RPC for connect QR
The OpenClaw mobile/companion app scans a pairing setup code to connect to the gateway, but that code + QR could only be produced by the openclaw qr CLI (ASCII to stdout). Non-terminal clients driving onboarding had no way to display the connect QR.
Add a device.pair.setupCode gateway method that reuses resolvePairingSetupFromConfig + encodePairingSetupCode + renderQrPngDataUrl to return { setupCode, qrDataUrl?, gatewayUrl, auth, urlSource }. The embedded setup code mints a short-lived bootstrap token that hands off broad operator scopes (read/write/approvals/talk.secrets), so the method requires operator.admin (matching the wizard methods a companion already uses) and is not advertised. auth is a label only; the gateway credential is never returned, and an oversized QR is omitted so the response always satisfies the result schema.
Refs #94661.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(ui): pair mobile devices from Control UI
* docs: refresh generated docs map
* docs: clarify mobile QR auto-connect
* docs: clarify mobile QR auto-connect
* docs: clarify mobile QR auto-connect
---------
Co-authored-by: Barbara Kudiess <76582160+bkudiess@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(ui): session-first sidebar, context ring, and warm light theme for Control UI
* test(ui): drop unnecessary non-null assertion in sidebar recents test
* Diagnose Windows LAN Gateway firewall blocks
* Fix Windows firewall diagnostic lint
* fix: gate gateway firewall diagnostics to local targets
* fix: keep firewall inspection off critical flows
Adds `messages.responseUsage` (precedence session -> channel -> config default
-> off) so the persistent /usage footer can default-on, with three distinct
states: explicit on (tokens/full), explicit off (persisted), and unset (inherit
the configured default).
Unifies effective-value resolution behind a single channel-aware resolver
`resolveEffectiveResponseUsage` used by reply rendering, the no-arg /usage
toggle, the ACP control, and the gateway session-row builder; the row builder's
`effectiveResponseUsage` is carried through sessions.changed events, chat
snapshots, and the UI row so live consumers never go stale. `/usage reset`
(aliases inherit/clear/default) clears the override to inherit; only explicit
off persists; a full session reset preserves the preference. ACP "Usage detail"
gains an "inherit" option for unset sessions. Docs/help/completions updated; "on"
documented as a legacy alias; config-doc baseline regenerated.
* fix(control-ui): make bootstrap config endpoint base-path-relative (#66946)
CONTROL_UI_BOOTSTRAP_CONFIG_PATH embedded a hard-coded /__openclaw prefix
instead of being base-path-relative. When the Control UI is served under
/__openclaw__/, both the gateway and the browser loader compose
${basePath}${CONTROL_UI_BOOTSTRAP_CONFIG_PATH}, producing the doubled
/__openclaw__/__openclaw/control-ui-config.json URL that 404s.
Make the constant base-path-relative (/control-ui-config.json) so the
composed URL is correct under any base path, align the Vite dev stub and
the docs, and add gateway.controlUi.basePath "/__openclaw__" coverage.
* fix(control-ui): serve bootstrap config at default __openclaw__ entry (#66946)
The reporter runs the default deployment (no gateway.controlUi.basePath),
so the Control UI SPA is mounted under the default /__openclaw__/ namespace.
A browser opening that entry infers basePath="/__openclaw__" from the URL
(inferBasePathFromPathname) and fetches /__openclaw__/control-ui-config.json,
but an empty-base-path gateway only served the bare /control-ui-config.json,
so the default-entry bootstrap request 404'd and chat never finished loading.
Make handleControlUiHttpRequest also accept the default-namespace alias
/__openclaw__/control-ui-config.json when no base path is configured. The
alias is derived from the existing CONTROL_UI_NAMESPACE_PREFIX mount constant
and is purely additive: the bare /control-ui-config.json endpoint and the
configured-base-path endpoint are both preserved (no route removed).
Add gateway HTTP coverage for the real default-entry scenario (empty base
path + /__openclaw__/... request) that fails without the alias, alongside the
configured-base-path, bare-path compatibility, and doubled-path 404 cases.
* fix(control-ui): preserve legacy bootstrap endpoint as compat alias (#66946)
Current main and v2026.6.1 serve and document the single-underscore
/__openclaw/control-ui-config.json bootstrap endpoint under an empty
base path (that literal was CONTROL_UI_BOOTSTRAP_CONFIG_PATH before the
path was made base-path-relative). Making the constant relative dropped
that match, so older bundles and clients hitting the documented endpoint
would 404 after upgrading.
Accept the legacy single-underscore path as an empty-base-path
compatibility alias in matchesControlUiBootstrapConfigPath, derived from
the legacy /__openclaw namespace joined with the canonical config
constant (so it tracks any filename rename) and named
LEGACY_BOOTSTRAP_CONFIG_PATH with a comment. The canonical
/control-ui-config.json and the default-namespace
/__openclaw__/control-ui-config.json aliases are unchanged; only this
path is added. The doubled /__openclaw__/__openclaw/... path still 404s.
Add a focused regression that the legacy endpoint returns config under an
empty base path; it 404s without the alias (verified non-vacuous).
* fix(control-ui): preserve legacy bootstrap route under configured base path (#66946)
The previous revision preserved the single-underscore
/__openclaw/control-ui-config.json bootstrap endpoint only under an empty
base path. A deployment with a configured gateway.controlUi.basePath
(e.g. /x) served and documented that endpoint at
${basePath}/__openclaw/control-ui-config.json before this PR made the
config path base-path-relative, so configured-base-path users, older
bundles, and clients that still request it would 404 after upgrading.
Extend matchesControlUiBootstrapConfigPath so the legacy single-underscore
suffix is accepted under every base path, not just the empty one. The
matcher now checks the canonical and legacy suffixes uniformly as
${basePath}${CONTROL_UI_BOOTSTRAP_CONFIG_PATH} and
${basePath}${LEGACY_BOOTSTRAP_CONFIG_PATH} for both the empty and
configured cases, reusing the existing LEGACY_BOOTSTRAP_CONFIG_PATH
constant (no new hard-coded literal). The default-namespace
/__openclaw__/control-ui-config.json alias stays empty-base-path-only
(it is the path the inferred default entry requests when no base path is
configured). All three empty-base-path behaviors are unchanged; the
doubled /__openclaw__/__openclaw/... path still 404s under both an empty
and a configured base path.
Add a focused regression that the configured-base-path legacy endpoint
returns the bootstrap config; it 404s without the alias (verified
non-vacuous). No CHANGELOG.md change.
* fix(ui): mount config stub under vite base
* fix(ui): preserve default config stub route
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Add a bounded `chat.message.get` gateway method so Control UI can fetch one display-normalized transcript message by id when an assistant history preview was truncated. Keep `chat.history` lightweight, reject oversized/hidden/missing rows with explicit unavailable reasons, and wire the WebChat side reader to request full content only for visible truncated assistant messages.
Also refresh the generated Swift gateway protocol models and document the new assistant-message side-reader behavior.
Closes#84651.
Related #53242.
Co-authored-by: NianJiuZst <3235467914@qq.com>
Refactor OpenAI provider identity so OpenAI remains the canonical provider for API-key and OAuth-backed flows while legacy openai-codex state is doctor/migration-only.
Keeps OpenAI Codex Responses as an API/transport class rather than a provider identity, moves auth aliases through providerAuthAliases, updates doctor repair sequencing for old auth/profile state, and refreshes tests/docs around the canonical OpenAI behavior.
Add read-only MCP visibility to `tools.effective` by projecting MCP tools only after a session catalog has already been warmed by an agent turn. Keep the gateway additive: no `tools.effective.refresh`, no forced MCP startup, and no behavior change for MCP loading.
Verification:
- `git diff --check origin/main..HEAD`
- `node scripts/run-vitest.mjs run --config test/vitest/vitest.agents.config.ts --reporter=verbose src/agents/tools-effective-inventory.test.ts`
- GitHub checks green on `a8a7f8442adb216f60da24d50118374a15c62e06`, including `Real behavior proof`, `check-guards`, `check-prod-types`, `check-test-types`, `build-artifacts`, `Critical Quality (gateway-runtime-boundary)`, and `Critical Quality (network-runtime-boundary)`.
Co-authored-by: David Huang <nxmxbbd@gmail.com>
Summary:
- This PR routes bare `openclaw` to classic onboarding for missing, empty, or metadata-only configs; keeps aut ... cs/changelog/tests; and narrows a Docker E2E boundary-check exception for an existing source-checkout lane.
- Reproducibility: not applicable. this is a feature/default-routing PR rather than a bug report. The branch p ... ill includes a fresh-state terminal run reaching `OpenClaw setup` and tests for the relevant config states.
Automerge notes:
- PR branch already contained follow-up commit before automerge: feat: start onboarding for fresh CLI installs
Validation:
- ClawSweeper review passed for head f4b2572f2e.
- Required merge gates passed before the squash merge.
Prepared head SHA: f4b2572f2e
Review: https://github.com/openclaw/openclaw/pull/85519#issuecomment-4522938004
Co-authored-by: FullerStackDev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- Sanitize Control UI form-mode config submissions after schema coercion and before config.set/config.apply.
- Drop stale redacted placeholders only when the loaded form also had the redaction sentinel and the original raw config lacks that path.
- Preserve restorable saved secrets and user-entered literal sentinels so the gateway's fail-closed validation remains authoritative.
Verification:
- node scripts/run-vitest.mjs ui/src/ui/controllers/config.test.ts ui/src/ui/controllers/config/form-utils.node.test.ts
- pnpm exec oxfmt --check --threads=1 ui/src/ui/controllers/config.ts ui/src/ui/controllers/config/form-utils.ts ui/src/ui/controllers/config.test.ts ui/src/ui/controllers/config/form-utils.node.test.ts docs/web/control-ui.md CHANGELOG.md
- git diff --check origin/main...HEAD
- pnpm check:changed
- GitHub PR checks green on head b35a5b975d
Adds a bounded browser-local Control UI text size setting in Appearance and Quick Settings, persists it in UiSettings, and applies CSS text-scale variables across chat text, composer input, sidebars, and tool cards while preserving mobile Safari input zoom safety.
Fixes#8547.
Thanks @BunsDev.
Summary:
- Add a plain HTML Control UI fallback when the module app never mounts.
- Document blank-page recovery guidance and keep the fallback retry-friendly.
- Cover the timeout path with iframe-isolated regression tests.
Verification:
- pnpm exec oxfmt --check --threads=1 ui/index.html ui/src/ui/mount-fallback.test.ts
- pnpm test ui/src/ui/app.talk.test.ts ui/src/ui/mount-fallback.test.ts
- pnpm ui:build
- pnpm check:changed
- GitHub CI for 8ef18e8bca completed without failures.