Preserve structured provider catalogs beyond the lifecycle log capture limit so the cloud machine picker shows CPU/RAM and all available classes again. Keep lifecycle output limits and machine selection unchanged.
Fixes#130660.
Keep raw recovery keys in explicitly opted-in JSON output. Add a safe text
hint in the CLI-owned result renderer, remove duplicated stored-key output,
and cover normal, verbose, missing-key and JSON command behavior.
Thanks @hartmark for the original fix and real-account reproduction.
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(agents): strip external-content nonce before loop-detection resultHash
External-content wrappers carry a fresh anti-forgery nonce per result
(createExternalContentMarkerId). The loop detector hashed the wrapper text
including the nonce, so identical failing wrapped tool calls never reached
the no-progress block threshold — the detector warned but never blocked,
leaving the agent to loop until it gave up (#130210).
Strip the wrapper nonce before hashing in extractTextContent, mirroring
the existing stripVolatileSendIds treatment of per-call send ids (#89090).
Only the hash is normalized; the delivered wrapper keeps its nonce, so
anti-forgery is unaffected.
Closes#130210
Co-Authored-By: Claude <noreply@anthropic.com>
* test(agents): validate protected error marker capture
Narrow the generated marker capture before recording it so the real network-error loop regression also passes its owning test-type graph.
---------
Co-authored-by: ruel225 <ruel225@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(github-copilot): preserve catalog thinking efforts in requests
Unify discovered and bundled capability mapping with the provider thinking policy. Preserve supported xhigh/max Responses efforts and map minimal to the supported low minimum, while respecting explicit account opt-outs and transport limits.
Fixes#107792
Co-authored-by: Pluviobyte <Pluviobyte@users.noreply.github.com>
* fix(github-copilot): resolve nullable thinking policy transport
Accept the public policy API context and resolve missing transports before enforcing Claude and Gemini effort restrictions. Cover undefined and null API values without changing explicit Responses routes.
* refactor(github-copilot): normalize manifest models as one catalog
Use the canonical batch model provider builder after the single-row helper was removed on main. Preserve model transport and compatibility decoration without a legacy API shim.
* refactor(github-copilot): decorate owned catalog rows in place
Keep the normalized manifest batch as the sole owner of runtime rows and apply transport metadata directly, avoiding redundant row copies.
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Pluviobyte <Pluviobyte@users.noreply.github.com>
Archived sessions now expose only non-mutating transcript actions plus fork, close stale interaction portals when archival arrives, and reject rewind or branch switching under the Gateway lifecycle lock.
Co-authored-by: vyctorbrzezowski <krzyszchweski@gmail.com>
* feat(channels): introduce bots when they join group rooms
* feat(channels): add Discord and Telegram join introductions
* fix(channels): isolate untrusted evidence and select allowed join targets
* refactor(channels): scope joinIntro to implementing channels
* fix(channels): keep a delivered join introduction settled when its durable commit fails
* feat(channels): read more room history and document join introductions in detail
* chore(config): regenerate bundled channel metadata after rebase
* fix(doctor): migrate deprecated bindings match.peer.kind dm to direct
Legacy 2026.7.x configs may still use match.peer.kind "dm", which the
current strict schema rejects while the docs call it a deprecated alias
for "direct". Doctor had no migration for it, so candidates kept failing
validation and the atomic write guard left the config unchanged,
blocking gateway startup after upgrade.
Rewrite dm to direct for all top-level bindings during doctor migration
and report the change; detection uses the standard legacy-rule path.
* test(doctor): cover binding migration boundary
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* fix(agents): node plugin tool calls report a generic client timeout
Plain node-hosted plugin tool calls send no invocation budget, so the Gateway
arms no deadline over pairing, wake, and policy work and the node registry falls
back to its own 30s pending timer that only starts at dispatch. The agent-side
wait defaults to the same 30s but starts earlier, so the caller always abandons
the request first and the Gateway answer that carries nodeCommandDispatched
retry-safety provenance can never arrive.
Send the same 30s budget explicitly and give the caller the +5s grace the node
MCP path already uses, so the Gateway answer wins the race.
* test(gateway): prove the node invoke deadline answer reaches the agent
Adds an end-to-end proof that runs a real Gateway, pairs a real node that
accepts the forwarded command and never answers, and drives the shipped agent
tool through the real gateway client. It asserts the agent receives the
Gateway's structured timeout with nodeCommandDispatched provenance rather than a
client-side gateway timeout.
* fix(gateway): keep node invoke dispatch inside the caller budget
The invocation budget only started once dispatch was reached, so pairing
revalidation before it spent nothing. With the Gateway deadline now armed for
plain node plugin tools, that let a send land after the deadline had already
answered the caller with nodeCommandDispatched:false, advertising a command the
node had in fact received as retry-safe.
Anchor the budget at entry and re-derive what is left after pairing
revalidation, refusing to dispatch once it is exhausted.
* test(gateway): restore the Gateway URL after the invoke deadline proof
The shared Gateway fixture does not snapshot OPENCLAW_GATEWAY_URL, so the
proof left later tests in the same worker pointing at its stopped ephemeral
server. Capture and restore the key, including its previously-unset case.
* fix(gateway): read the node invoke budget after request serialization
Pairing revalidation is not the only step that can spend the caller budget
before the pending timer is armed: tool parameters are unbounded, so
serializing them and resolving the pending system.run event can outlive the
remaining budget on their own.
Reading the budget once all of that work is behind the call site keeps the node
timeout and the pending timer starting from what is actually left, so an
exhausted budget refuses the dispatch instead of arming a timer that answers
after the caller already reported a timeout.
* test(gateway): pin node invoke dispatch provenance against a budget-consuming send
The review asked for the final event envelope to be serialized before the
deadline admission check, on the grounds that a slow serialization could let
the Gateway report nodeCommandDispatched: false for a command the node did
receive. Envelope build, send and onDispatchReady are one synchronous block,
so nothing can settle the pending request between them. Pin that invariant
with a send that spends the whole remaining budget.
* test(gateway): type the node socket send mock with its call signature
The budget-consuming send regression wraps the recorded socket send, and
ReturnType<typeof vi.fn> resolves to a mock without a call signature, so
tsgo rejected the wrapper with TS2348 while vitest ran it fine.
* test(gateway): follow the node pairing helpers into device-pairing-node
main folded src/infra/node-pairing.ts into src/infra/device-pairing-node.ts,
so the deadline proof stopped resolving its pairing import after the merge.
* fix(gateway): scope the invoke deadline to caller-supplied budgets
Callers that omit timeoutMs, such as fs.listDir and the exec-approval
paths, have always used the registry's 30-second fallback as a
post-dispatch pending timer. Anchoring that fallback before pairing
revalidation turned it into a dispatch admission check, so a slow
revalidation could answer TIMEOUT without ever dispatching. Only a
positive caller-supplied budget anchors the deadline now, which keeps
the plain plugin-tool path covered while those callers keep their
established semantics.
* fix(test): import approveDevicePairing from its new module
main split the device pairing lifecycle modules in #124734 and moved
approveDevicePairing to src/infra/device-pairing-approval.ts. Nothing on
either side touched this import line, so the merge stays conflict free
and only the typecheck reports the missing export.
* refactor(gateway): move node invoke deadline budget to a sibling module
node-registry-private.ts sits at 693 counted lines on main against a 700-line
max-lines ratchet, and the inline budget bookkeeping pushed it to 703, which is
what turned check-lint-core-2 red. The budget arithmetic moves to
node-registry.invoke-budget.js unchanged; the call site keeps the same two reads.
* refactor(gateway): move system.run invoke helpers to their sibling module
The max-lines ratchet caps src/gateway/node-registry-private.ts at 700
effective lines and main now sits at 699, so the dispatch budget guard
this branch adds takes the file to 705 and check-lint-core fails.
resolvePendingSystemRunEvent and normalizeSystemRunInvokeParams are
module-private and both already delegate to normalizeSystemRunTimeoutMs
in node-registry.system-run.ts, so that module is where they belong.
Pure move: no behavior change and no new export surface.
* fix(gateway): keep the moved system.run helpers within the ratchet baselines
The previous commit moved resolvePendingSystemRunEvent and
normalizeSystemRunInvokeParams into node-registry.system-run.ts. It changed no
behavior, but it did move three per-file measurements.
normalizeSystemRunTimeoutMs was exported because node-registry-private.ts
consumed it; the two callers that moved were its only external consumers, so
after the move the export had none and Knip reported it as an unused production
export. It is module-private now.
The moved code also carried two `as Record<string, unknown>` assertions that
were grandfathered under the old file. The new file's baseline is 0, so both
now carry the // SAFETY: invariant the ratchet asks for, and the source file's
baseline entry is shrunk from 3 to 1 as the ratchet's own message requested.
* test(gateway): fix typed node invoke serialization fixture
Close over the typed execution payload instead of reading contextual this
inside toJSON, whose surrounding invoke params contract is unknown.
Keep the serialization delay and independent execution-budget assertions.
The 141 registry tests and focused canonical-inherited test type graph pass.
Co-authored-by: Yigtwxx <yigiterdogan023@gmail.com>
* docs(changelog): avoid node deadline entry merge conflict
Move only this PR's credited release-note entry beside the existing Gateway
client watchdog entry, away from the concurrently edited section boundary.
The entry and tested runtime behavior are unchanged.
Co-authored-by: Yigtwxx <yigiterdogan023@gmail.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* [AI] fix(plugins): filter pnpm parent-child overrides at managed npm producer
readOpenClawManagedNpmRootOverrides returned host pnpm-workspace overrides
without filtering pnpm-only parent-child selectors (parent>child). Those
selectors are invalid npm override keys and trigger EINVALIDTAGNAME before
the retry-based compatibility path can recover, breaking managed npm plugin
installs and the pre-install peer-sync that runs before the retry loop.
Filter pnpm parent-child selectors once at the shared producer so every
managed npm install/uninstall consumer receives a npm-compatible manifest
up front. The existing retry path stays as a fallback for npm alias
compatibility, which is npm-version-dependent.
Fixes#124426
* fix(plugins): normalize overrides before managed peer planning
Plan peers against the incoming compatible override set so retired selectors cannot silently retain stale pins. Remove duplicate selector retry and synchronization paths while preserving npm alias compatibility.
Co-authored-by: WangYan <wang.yan29@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Use the transcript mutation version to refresh a startup snapshot when a write races initial history loading. Subscribe before the queued initial history runs and remove duplicate sent-history state.
Bound Doctor’s media migration memory and SQLite crossings with one composite-key cursor. Preserve the existing exact-row writer and transaction behavior while preventing full-scan pagination.
Co-authored-by: Ahmad Shawwal <62305104+ashawwal@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(codex): reclaim binding ownership when sessions are deleted
Prepare harness deletion outside the SQLite writer and compare-delete exact companion ownership at the session removal edge, with compensation before commit and native subscription release afterward. Preserve live siblings and upstream native history. Repair proven orphan bindings through the existing Doctor planner under maintenance ownership.
* fix(codex): reuse prepared auth for resumed thread ownership
* docs(plugins): clarify shared migration and auth contracts
* test(codex): use the canonical config type facade
* fix(codex): preserve native threads during manual resume
Record pending attachment intent and validate the immutable native tool catalog
before applying configuration to the selected thread. Require uninterrupted
physical-client ownership through native unsubscribe, resume, and binding commit.
Keep the thread intact on unsupported policy, competing work, or failed proof.
Reuse canonical retained-owner cleanup and preserve unsafe-client retirement.
Cover the real command producer, cold and loaded resumes, competing leases,
lazy-store commit fencing, and the Gateway competing-owner path.
* test: isolate Codex auth and session completion fixtures
Retire node-wide projections and subscriptions synchronously after unregistering the exact connection so delayed disconnect history cannot erase a replacement connection.
* fix(memory): isolate sqlite-vec KNN in subprocess
* fix(memory): satisfy KNN subprocess CI guards
* test(release): include memory KNN child artifact
* test(memory): update KNN subprocess fixtures
* fix(memory): bound KNN child row payloads
* fix(memory): preserve published readers during cancellable KNN
Keep shadow reindex database, vector readiness, FTS and metadata state in
an owned async context. Public operations retain the published connection,
and escaped shadow continuations cannot write to it after rebuild closes.
Terminate the one-shot query child through its owned handle and retain
admission until close. Remove process-tree/PID probing and test-only hooks.
Cover publication overlap, callback reads, cancellation and recovery.
Co-authored-by: OpenClaw Assistant <assistant@openclaw.local>
* refactor(memory): separate database context ownership
Keep the published reader and shadow writer context in its own owner module. Repair plugin test imports and typed lint findings without changing the verified KNN behavior.
---------
Co-authored-by: OpenClaw Assistant <assistant@openclaw.local>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Persist required completion payloads before delete cleanup so Gateway restart can replay safe pending work after the child session is gone. Preserve durable session-queue ownership and #129993 per-Gateway resolver behavior without a schema change.
Co-authored-by: MertBasar0 <mertbasar0@hotmail.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Install public Node and Corepack artifacts in one strict root child shell
with umask 022, leaving the caller's private umask unchanged.
The real sanitized AWS bootstrap failed with exit 127 under umask 0077:
root-owned 0700 installation directories hid the installed Node binary
from the non-root caller. The same-host corrected run completed the
pinned Node 24.19.0/pnpm 11.22.0 install and verified readable public
artifacts, caller umask 0077, temporary HOME 0700, and private files 0600.
Existing bootstrap tests: 2 passed. Shell checks and both required
independent reviews passed. The real privileged-install reproduction is
retained instead of adding a brittle extracted-source installer harness.
Treat LIKE fallback as recall-only so memory search no longer reports false perfect scores. Carry the body-match fact through keyword and hybrid ranking to preserve lexical ordering, including exact path tiers.
Co-authored-by: SunnyShu0925 <shu.zongyu@xydigit.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Put the full-item equality boundary before expensive row preparation, preserving the existing disclosure state and diff semantics. Related to #124759; controlled shared-view updates improve without changing initial diff preparation.