* refactor: extract reusable AI runtime package
* refactor: complete AI provider relocation
* refactor: keep llm core internal
* refactor(ai): make @openclaw/ai self-contained with host policy ports
Move pure transport helpers (tool projections, strict-schema normalization,
prompt-cache boundary, stream guards, anthropic/openai compat, request
activity) from src into packages/ai; move utf16-slice into
normalization-core. Inject host policy (guarded fetch, redaction,
strict-tool defaults, diagnostics logging) through AiTransportHost with
inert library defaults installed by src/llm/stream.ts. Narrow the public
barrel to instance-scoped createApiRegistry/createLlmRuntime; the
process-default runtime moves behind internal/ and
registerBuiltInApiProviders takes an explicit registry. Delete the
src/llm/api-registry re-export facade.
* fix(ai): teach node, jiti, and vite resolvers the @openclaw/ai and utf16-slice subpaths
The workspace alias tables in root-alias.cjs, plugin-sdk-native-resolver,
sdk-alias, the shared vitest config, and the Control UI vite config only
knew @openclaw/llm-core; Node-side plugin loading resolved @openclaw/ai
through the pnpm symlink to the unbuilt dist (checks-node-compact CI
failures), and the Control UI build broke on the new
normalization-core/utf16-slice subpath.
* chore(ui): drop leftover service-worker debug logging
* build(release): ship @openclaw/ai with its own shrinkwrap and honest dependency set
packages/ai declares only its six real runtime deps (kysely, chalk, json5,
tslog, zod, fs-safe, and proxyline were never imported); orphaned root deps
removed. generate-npm-shrinkwrap now treats publishable packages/* like
publishable plugins so the AI tarball pins its transitive tree even though
workspace deps are omitted from the root shrinkwrap. knip learns the
package entry points; the tsdown dts neverBundle option moves to its
documented deps.dts home; the README documents the no-semver internal/*
contract and host ports.
* docs(ai): add minimal external-consumer example app
examples/ai-chat consumes only the public @openclaw/ai surface (built dist
via the workspace link): isolated runtime, built-in provider registration,
one streamed completion. Supports Anthropic/OpenAI via env keys and a
keyless local Ollama target; live-verified against Ollama.
* docs(ai): document the @openclaw/ai package and workspace shrinkwrap boundary
* chore(check): include examples/ in duplicate-scan targets
* fix: emit normalization package subpaths
* fix: complete AI package boundary artifacts
* fix: align AI package boundary contracts
* fix(ci): stabilize package release contracts
* test: align documentation contract checks
* test: keep cron docs guard aligned
* test: align restored docs contract guards
* test: follow upstream docs contracts
* docs: drop superseded talk wording
Allow busy TUI sessions to forward prompts into the configured queue while
keeping queued-turn admission, cancellation, restart, and transcript ownership
consistent across the TUI, Gateway, and followup queue.
Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
Refactor the Control UI around route-owned page lifecycle and state while preserving existing behavior and design.
Prepared head SHA: bd51b6fa76
Co-authored-by: Shakker <165377636+shakkernerd@users.noreply.github.com>
Reviewed-by: @shakkernerd
Prevents opted-in plugin runtime dependencies from being published with stale
registry pins. The same freshness assertion now guards both npm and ClawHub
release paths, including the managed Codex runtime.
Prepared head SHA: d5d0ecba4b
Reviewed-by: @fuller-stack-dev
Closes#99951
The node_modules package-root boundary fix anchors bundled plugin
discovery to the running checkout in nested worktrees, so the wrapper
no longer needs to pin OPENCLAW_BUNDLED_PLUGINS_DIR for symlinked
node_modules layouts. Verified live in a .claude worktree: with the
boundary fix and no pin, vitest workers resolve the worktree's own
extensions in both no-node_modules and symlinked layouts, and linked
worktrees now follow the same canonical dist-preferred discovery as
normal checkouts. The trust env remains owned by test/setup.shared.ts.
Must land together with or after the boundary fix commit directly below.
Accept the documented package-manager separator for the web fetch benchmark CLI and add a process-level regression test. Verified with rebased Testbox check:changed, prior targeted Testbox benchmark/test smokes, and AWS macOS install/build/gateway probes.
* fix(infra): stop package-root walks at node_modules boundaries
Nested git worktrees (.worktrees/<pr>, .claude/worktrees/*) have no local
node_modules, so vitest workers run with argv1 inside the enclosing
checkout's node_modules. resolveOpenClawPackageRoot* walked up past that
boundary, resolved the enclosing checkout as the openclaw package root,
and bundled plugin discovery loaded the ancestor's stale extension
manifests, failing ~12 test shards and the scripts/pr prepare-run test
gate whenever the primary checkout sat on a different branch.
A package.json above a node_modules directory belongs to the workspace
that installed the tooling, never to the package owning the running code,
so the ancestor walk now stops there. Installed layouts
(node_modules/openclaw, .bin shims, global installs) match at or below
the boundary and are unaffected.
* fix(scripts): pin bundled plugin discovery in nested PR worktree gates
scripts/pr gates run pnpm test inside .worktrees/<pr>, which resolves
vitest tooling from the primary checkout's node_modules. PR branches that
predate the openclaw-root node_modules-boundary fix would still discover
the primary checkout's stale bundled plugin manifests, so pin
OPENCLAW_BUNDLED_PLUGINS_DIR to the worktree's own extensions before the
build/check/test gates.
* 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>
* fix(build): forward default exports through stable runtime aliases
runtime-postbuild writes stable aliases (`X.runtime.js`) for hashed runtime
chunks as bare `export * from "./X-HASH.js"` — but `export * from` never
re-exports `default`. In the shipped 2026.6.10/2026.6.11 artifacts the
compaction runtime alias points at a chunk whose only export is default, so
its lazy consumer destructuring `{ default: reconcile }` gets undefined:
every successful auto-compaction logs "late compaction count reconcile
failed: TypeError: reconcile is not a function" and the persisted
compactionCount never updates. On local-model deployments the resulting
repeat compactions each cost a multi-minute full re-prefill (observed:
3 compactions in 25 minutes). Other stable aliases are latent instances of
the same generator defect for any target that gains a default export.
Fix: when the alias target has a default export, also emit
`export { default } from ...` (applies to both the stable-alias and
legacy-compat writers). Detection is an anchored export-statement pattern,
verified against all 7 shipped runtime chunks (no false positives; naive
text matching would both miss and over-match — an alias claiming a default
its target lacks is a hard SyntaxError at import). Adds a regression test
mirroring the real compaction-reconcile chunk shape.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6Hz9UEpxQ4W3d8XecvupH
* fix(build): preserve defaults through legacy runtime aliases
---------
Co-authored-by: headbouyJB <23249268+headbouyJB@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Summary:
- The PR changes the docs map generator to escape HTML-significant heading text, regenerates `docs/docs_map.md`, and adds a Vitest regression for HTML-like headings.
- PR surface: Tests +13, Docs 0, Other +10. Total +23 across 3 files.
- Reproducibility: yes. Current main has source headings such as `docs/cli/agents.md:164` with `<id>`, while `docs/docs_map.md:1231` omits it and `scripts/generate-docs-map.mjs:90` strips `<...>` text.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 261466a2a8.
- Required merge gates passed before the squash merge.
Prepared head SHA: 261466a2a8
Review: https://github.com/openclaw/openclaw/pull/99099#issuecomment-4866739708
Co-authored-by: Mason Huang <masonxhuang@tencent.com>
Approved-by: hxy91819
Summary:
- The PR replaces native i18n conditional-branch regex filtering with an exported linear ASCII scanner and adds focused coverage.
- PR surface: Tests +9, Other +36. Total +45 across 2 files.
- Reproducibility: yes. from source inspection: current main routes conditional-branch native literals through the backtracking-prone regex before inventory output. I did not run a timing benchmark against current main.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 97464c9635.
- Required merge gates passed before the squash merge.
Prepared head SHA: 97464c9635
Review: https://github.com/openclaw/openclaw/pull/99098#issuecomment-4866733462
Co-authored-by: Mason Huang <masonxhuang@tencent.com>
Approved-by: hxy91819