Code mode previously suspended to the model with a waiting result for every
awaited tools.search/describe/call, forcing one wait tool turn per await
(turns = tool calls + 1). Bridge calls now resolve inline within the exec
deadline and resume the QuickJS snapshot host-side, matching the namespace
auto-drain path. Restart-safe runs keep their existing no-drain semantics.
Live proof across OpenAI/Anthropic/Google: ~45% fewer turns and ~45% fewer
input tokens at equal success rate.
Also landed with the same contract:
- one shared wall-clock deadline per exec/wait call (initial worker, inline
drain rounds, and resumed guest interrupt budget all share it)
- park the snapshot instead of resuming when the remaining budget could not
survive VM restore, so near-deadline settles stay recoverable
- abort now terminates the guest worker, skips resume, and drops suspended
runs instead of pinning process-global slots until TTL, reported with the
existing aborted failure code
- exec description omits API.list/MCP/namespace guidance when the run catalog
has no MCP tools or namespaces, so models stop probing an empty surface
- API.list tolerates a trailing-slash prefix like API.list("mcp/")
* fix(agents): map cacheRetention 'standard' to 'short' for Bedrock Claude models
* fix(agents): scope standard cacheRetention alias to Anthropic cache family only
* fix(agents): validate prompt cache retention
* chore: keep changelog release-owned
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Stops the legacy run-log dual-write, auto-imports remaining rows and drops
the table at state-DB open (table-presence guard: self-heals downgrade
round-trips), keeps the newest 2000 terminal runs per job in the ledger,
retires cron.runLog config via doctor, and moves live-run cancellation to
src/cron behind the shared task control seam.
Part 2 of 2 for #106041.
* fix(memory): scope qmd search deadline
Preserve the phase-scoped QMD timeout semantics on current main.
Co-authored-by: Peter Steinberger <58493+steipete@users.noreply.github.com>
* docs: refresh generated docs map
* test(memory): reconcile manager mock with current main
* test(memory): isolate deadline mock import
* style(memory): format search test mocks
* test(memory): decouple mock from deadline symbol
* chore(memory): refresh reviewed pull request head
---------
Co-authored-by: Benjamin Badejo <ben@benbadejo.com>
Co-authored-by: Peter Steinberger <58493+steipete@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
* refactor(sessions): migrate runtime storage to sqlite
* test(sessions): fix sqlite CI regressions
* test(sessions): align remaining sqlite fixtures
* fix(codex): require sqlite trajectory recorder
* test(sessions): align orphan recovery sqlite fixture
* test(sessions): align sqlite rebase fixtures
* fix(sessions): finish current-main integration of the sqlite flip
Resolve the whole-store SDK removal across its owner boundary: drop the
loadSessionStore re-export and the registry whole-store wrappers, wire
hasTrackedActiveSessionRun into gateway chat, complete the
preserveLockedHarnessIds cleanup contract, flip the codex thread-history
import to storePath targets, and port remaining main-side tests from
file-store helpers to session accessor reads.
* chore: drop committed pebbles log, revert plugin-inspector bump, refresh generated docs
Remove the 1.8k-line .pebbles/events.jsonl work log from the branch, restore
the plugin-inspector advisory lane to main's pinned 0.3.10 so the supply-chain
bump gets its own review, and regenerate docs_map, the plugin SDK API baseline,
and the export-surface ratchet for the merged tree.
* feat(sessions): keep archived transcripts by default with zstd cold storage
Codex-style retention: deleting or resetting a session archives its
transcript as a zstd-compressed JSONL artifact (plain when the runtime
lacks node:zlib zstd) and keeps it until the disk budget evicts oldest
first. resetArchiveRetention now governs both deleted and reset archives
and defaults to keep; maxDiskBytes defaults to 2gb so retention stays
bounded, with archives evicted before live sessions. The cron reaper
follows the same knob instead of deleting archives on its own timer.
* fix(state): converge agent DB migration lineages and bound database growth
Merge coherence: run both structure-gated legacy memory-schema repairs
(flip-lineage drop, main-lineage identity rebuild) before the flip
migration so pre-flip v1/v2 and pre-merge flip v1/v4 databases all
converge, and hoist foreign_keys=OFF outside the schema transaction
where the pragma was silently ignored and the v1 sessions rebuild
cascade-deleted session_entries.
Growth guards: fresh agent DBs enable auto_vacuum=INCREMENTAL, WAL
maintenance releases freed pages in bounded passes (never a blocking
full VACUUM), and doctor reports state/agent DB bloat from freelist
stats.
* fix(codex): resolve the store path for thread-history import via the SDK
The supervision catalog passed the legacy sessionFile locator to the
storePath-targeted transcript mirror; resolve the agent store path with
the session-store SDK helper instead of a runtime-object seam so test
fakes and headless callers need no extra surface. Drop the obsolete
missing-session-id preprocessing case: sessions rows are NOT NULL on
session_id and upsert repairs id-less patches at write time.
* fix(sessions): fail safe on malformed disk-budget config and doctor stat errors
A malformed explicit maxDiskBytes disables the budget instead of
falling back to the destructive 2gb default the user never chose, and
the doctor bloat check skips databases whose paths stat-fail instead of
aborting doctor.
* fix(sessions): complete sqlite conflict translations
* test(sqlite): align hardening checks with maintenance
* test(sessions): inspect compressed transcript archives
* fix(tests): await session seeds and drop unused helpers flagged by CI lint
The five unawaited writeSessionStoreSeed calls raced their SQLite seeds
against the assertions, failing compact shards; the bloat probe drops a
useless initializer and the merged tests drop now-unused helpers.
* test(sessions): type legacy proof events directly
* test(sessions): align hardening contracts
* perf(sessions): read usage transcript sizes from SQL aggregates
Usage/cost scans walked every session and materialized every transcript
event just to re-stringify it for a byte estimate — the #86718 stall
class reborn on the DB. readTranscriptStatsSync sums stored JSON bytes
in SQLite without loading a single row.
* fix(sessions): re-root foreign-root transcript paths onto the current sessions dir
Restored backups, moved OPENCLAW_STATE_DIR, and rehearsal copies carry
absolute sessionFile paths from the old root; the containment fallback
kept those foreign paths, so migration read (and would archive) files in
the original root and reported local copies missing. Re-root the
canonical agents/<id>/sessions suffix onto the current dir when the file
exists there; genuine cross-root layouts still fall through unchanged.
* test(agents): seed harness admission through sqlite
* fix(sqlite): close agent db on pragma setup failure
* fix(doctor): compact and retrofit incremental auto-vacuum after session import
The migration is the sanctioned offline window: post-import compact
reclaims import churn and applies auto_vacuum=INCREMENTAL to databases
created before the fresh-DB pragma existed, so runtime maintenance can
release pages in bounded passes on every install.
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* test: wire Control UI suite into CI, fix its broken tests, drop dead harness surface
- fix 7 Control UI tests broken on main: module-mock factories are unreliable
under isolate:false shared workers; use RealtimeTalkSession prototype spies
and real jsdom storage instead (chat-realtime, chat-pull-requests)
- add gated checks-ui CI job (runUiTests changed-scope output): chromium
provisioning, lint:ui:no-raw-window-open, pnpm --dir ui test; ~30s on a
4vcpu runner, runs only when ui-affecting paths change
- add weekly node22-compat workflow exercising the supported lower Node bound
with the same command set as the dispatch-only ci.yml job
- delete the unreachable channels entry in EXTENSION_TEST_CONFIG_ROUTES and
the never-populated extensionRoutedChannelTestFiles override machinery
(born empty in 2ccb5cff22); resolved globs are provably identical
- guard run-vitest.mjs hardcoded path maps with existence tests so renames
cannot silently drop extended stall watchdogs
- remove unenforced coverage thresholds; test:coverage is informational, docs
updated (reference/test, help/testing, plugins/sdk-testing)
Closes#104321
* test: pin OPENCLAW_CI_RUN_UI_TESTS in the manifest env expectation
* test(ui): capture the realtime start spy instead of referencing the unbound prototype method
* test(ui): raise ui vitest timeouts for real-browser layout tests on small CI runners
Codex review: version existence alone does not prove the npm registry
serves the tarball this tag's preflight built — the same version could
have been published from a different artifact and npm versions are
immutable. The resume resolver now downloads the preflight manifest,
requires its releaseSha to match the target, and compares the published
registry tarball's sha256 against the manifest before skipping the core
dispatch; mismatches abort with correction-tag guidance.
The 2026.7.1 retro measured ~13h tag-to-published for beta.2 and stable
2026.6.11; any post-npm failure previously hard-aborted retries because
the already-published guard refused the whole run.
- resolve_openclaw_npm_publish_state replaces the abort guard: an
already-published core version skips the core npm dispatch and resumes
the remaining stages; verify_published_release still proves the
registry state matches the tag before the page leaves draft.
- Windows and Android promotion runs concurrently with the core npm
publish (their only shared prerequisite is the draft release page,
which is now created before the dispatch) and each promotion
short-circuits when the release already carries its verified asset
contract, so retries only redo failed stages.
- The release proof cites the core npm run only when this run dispatched
one; resumed publishes rely on the registry package check.
Two competing release-notes pipelines existed: the release branch's
hardened render/verify/provenance pipeline (a486f3ab08 + dcee1da876,
battle-tested by 2026.7.1) and main's lighter prepare-github-release-notes
size gate (#103222). Repo policy is one canonical path; the release-branch
pipeline wins and main's unique value is grafted in:
- scripts/render-github-release-notes.mjs becomes the canonical release
body renderer (full/compact 125k char+byte modes, tag-pinned record
link, verification tail, canonical shipped-baseline format), now also
preferring a correction tag's dedicated changelog section (from
prepare's heading matrix).
- verify-release-notes.mjs is a three-way merge: release's --shipped-ref
cumulative baselines, provenance checks, highlights gate, and the
excluded-record rewrite fix, plus main's compact contribution rows,
externalReferences threading, and both-heading parser compat.
- release-candidate-checklist.mjs gains validateCandidateCheckout and
changelog-provenance gates that run before any dispatch.
- openclaw-release-publish.yml keeps main's fail-before-mutation early
notes gate (retargeted to the renderer) and adopts release's
render/verify_release_tag_target/canonical_release_body_matches flow.
- scripts/prepare-github-release-notes.mjs and its test are deleted;
release-notes-ledger.test.ts stays and pins the merged verify exports.
- .gitignore tracks every repo skill for Git-aware syncs; SKILL.md
runbooks and RELEASING.md document the converged contract.
- Full Release Validation now checks for a prior green validation whose
target differs only by release metadata (changelog/version stamps) and
reuses that evidence instead of re-running every lane; disable with
reuse_evidence=false. Evidence manifests chain through reuse runs via
evidenceReuse.runId and the summary re-verifies the chain root.
- The Docker runtime-assets preflight no longer serializes the CI,
plugin-prerelease, release-checks, and performance lanes; it runs in
parallel and stays enforced by the umbrella verifier.
- Umbrella runs for release/* refs now supersede in-progress runs with
the same ref and rerun group instead of requiring manual cancels.
- release_profile=beta treats the live-provider E2E suites as advisory
(third-party model deployments move underneath releases); stable and
full profiles keep them blocking, and beta live failures no longer
fail-fast-cancel the remaining release-check matrix.
Gateway (additive, no protocol version bump): SessionEntry gains
lastReadAt/markedUnreadAt/lastActivityAt; session rows expose a derived
unread flag (explicit mark, or last read before latest activity; never-read
sessions stay read so upgrades do not light up). lastActivityAt is stamped
in the canonical post-run store update - user, channel, and cron runs count
as activity; heartbeat, internal-event, and preserved-state runs do not.
sessions.patch gains unread; sessions.create gains fork (transcript fork
from parentSessionKey under the parent lifecycle lock, refusing active,
concurrently-changed, and oversized parents, cross-agent aware).
Web sidebar: Pinned/custom-group/Ungrouped sections, unread dots, kebab and
right-click context menu (pin, mark unread/read, rename, fork, move to group,
archive, delete guarded for agent main sessions and active runs), mark-read
on view with loop-safe re-acknowledgement and failure retry; sessions page
gets unread + fork actions and shared custom-group helpers.
iOS Command Center: grouped sections, unread/pin indicators, Show Archived
gated on per-entry state, full context menu with rename/new-group alerts and
delete confirmation, current-session preview guarantee, read-episode
re-acknowledgement; new patch/delete/fork transport calls; Swift protocol
models regenerated.
Android SessionsScreen: grouped headers, unread/pin indicators, Archived
filter gated on per-entry state, long-press menu with the full control set,
agent-scoped forks, explicit label/category clears from session events,
main-session fallback when archiving/deleting the open chat, read-episode
re-acknowledgement with failure retry.
Closes#100739