* fix(worker): preserve Responses replay across handoff
Long OpenAI Responses cloud-worker sessions retain authoritative compaction replay through windowing and fail visibly when it cannot be preserved.
* test(worker): align replay fixture with frame limit
* [AI] fix(sessions): archive cron-run transcripts pruned by tasks maintenance
openclaw tasks maintenance --apply pruned stale cron-run session entries and
hard-deleted their SQLite transcript rows without writing the compressed
.deleted archive every other removal path writes (cron reaper, cleanup
service, heartbeat, doctor). The removal list built in
pruneSessionRegistryStore never set archiveRemovedTranscript, so the
downstream projection archived nothing while the rows were reclaimed
unconditionally.
Set archiveRemovedTranscript: true on the removal, matching the cron session
reaper. The existing archive machinery then writes and verifies the
.deleted.<ts>.zst cold copy before rows are reclaimed, so operators keep the
automation transcript under the archive retention policy.
Fixes#119269
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* [AI] test(sessions): recognize plain transcript archives in maintenance regression
ClawSweeper P2 on #119485: the archive-discovery helper only matched
.deleted.*.zst, but encodeSessionArchiveContent emits a plain JSONL
deleted archive when zstd is unavailable (e.g. Bun). Use the shared
isRetainedSessionTranscriptArchiveName classifier so the apply regression
accepts both supported archive encodings.
Related to #119269
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test(sessions): strengthen maintenance archive proof
Co-authored-by: SunnyShu0925 <shu.zongyu@xydigit.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(google): reject malformed video operation JSON
* fix(google): reuse shared provider JSON reader for video operations
Route successful Google video operation responses through the canonical
readProviderJsonResponse so fatal UTF-8 decoding and malformed-JSON wrapping
stay on the shared provider contract. Keep the lenient non-OK detail path.
* fix(agents): honor per-agent context budgets
Apply the selected agent contextTokens ceiling to embedded-run prechecks, effective model sizing, compaction, safeguard sizing, and result metadata. Prepared attempts now carry one canonical budget into extension setup instead of re-resolving mutable policy.
Caller-requested compaction budgets remain bounded by both the selected agent cap and the model window. Native model-owned harnesses continue to own their context and compaction policy.
Refs: #118678
Co-authored-by: harjoth <harjoth.khara@gmail.com>
* test(agents): type compaction model fixtures
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(cloud-workers): serialize accepted workspace rollback
Prevent rollback and recovery from racing a remote accepted-workspace apply after SSH loses its exit status. Settle the same transaction nonce under a durable phase lock before deciding whether publication succeeded.
Refs #120655
* refactor(gateway): keep workspace apply classifier private
* refactor(gateway): split accepted workspace lock script
* refactor(gateway): isolate accepted workspace lock
Keep the byte-identical remote lock fragment with the accepted-workspace transaction instead of the manifest implementation.
* test(gateway): fix settle manifest timing assertion
* fix(cloud-workers): preserve indeterminate workspace publication
Keep remote and local rollback journals pending when accepted-workspace settlement cannot be observed. Recovery now owns restoring both sides, while definitive apply and commit failures still roll back immediately.
Refs #120655
* perf(doctor): keep bundled doctor contract closures dependency-light
Doctor contract enumeration cold-loads each plugin's doctor-contract-api
closure via jiti, so a static value import of openclaw/plugin-sdk/runtime-doctor
pulled the state-db/kysely graph (~4.3s per closure) into
listPluginDoctorLegacyConfigRules / listPluginDoctorStateMigrationEntries.
- migrate all light doctor-contract closures (66 files) to the
dependency-light openclaw/plugin-sdk/runtime-doctor-migrations subpath
- voice-call: load detect/repairOpenClawStateDatabaseSchema* lazily inside
the migration bodies; keep only a type-only static runtime-doctor import
- matrix: split pure credential record shapes/normalizers into
credentials-state.ts so the doctor closure no longer imports the sync
plugin-state store through credentials-read
- guard: doctor-contract-closure-guard.test.ts now forbids static value
imports of runtime-doctor in closures alongside agent-runtime
* fix(matrix): keep credential revocation record type module-local
Knip production scan flags the export as consumer-less; the type is only
referenced by the exported union and revocation guard signature.
* fix(ui): report dev checkout update status
Show tracked-upstream commit lag and verified install/commit timestamps in Settings > Updates. Verify the post-restart Git revision before reporting success, and surface same-revision updates as an explicit no-op unless plugin convergence changed the install.
* test(ui): expect authoritative update reconciliation
Fresh Dev installs now preflight disk space and stream honest stages, while Codex activation probes the refreshed request-scoped registry.
Closes#120779Closes#120780
* fix(plugins): retain incognito scope for embedded session ownership
* fix(plugins): scope embedded ownership at run boundary
Keep the shared multi-identity gateway checker fail-closed while carrying the exact embedded session key agent and incognito store into its ID/file scan. Add real SQLite proof for accepted and foreign locked identities in one incognito store.
* style(plugins): format SQLite ownership regression
---------
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Debug capture clones every response and reads the clone under a byte cap, but
with no bound on how long it waits between chunks. A remote that sends headers
and one chunk and then goes silent leaves that read outstanding forever — and
because clone() tees the body, a branch settles its cancellation only once both
branches cancel or the source reaches EOF. So the caller's own cancellation,
and the guarded transport release that follows it, end up waiting on a
diagnostic read of a body nobody wants.
Read through the shared idle-bounded reader instead. On timeout it issues the
branch cancel fire-and-forget and throws, which is what lets the tee settle;
capture then records the exchange as metadata with bodyCapture "stalled",
alongside the existing too-large and unavailable cases. A stalled remote must
not turn a diagnostic read into a failure of the request being observed.
That helper also rejects when the read itself fails, and only the deadline is
capture's decision to make: a reset or aborted stream is the exchange failing
and still has to reach the error handler, so capture supplies its own timeout
error and rethrows anything else.
The response wrapper's cancel-then-release ordering is deliberate, pinned by
its own test, and stays untouched.
Co-authored-by: Peter Steinberger <steipete@gmail.com>