Keep retired auth-profile lookup on the lightweight provider-policy path so generic auth resolution no longer cold-loads provider runtimes.
Refs #129052
Stop OpenClaw from copying or refreshing Claude CLI OAuth tokens.
Claude CLI now owns native login and refresh state; Doctor removes retired copies while preserving CLI routing.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(cli-runner): drop stock watchdog defaults from CLI backend descriptors (#125045)
The claude-cli and gemini-cli backend descriptors spread
CLI_FRESH/RESUME_WATCHDOG_DEFAULTS into config.reliability.watchdog.
Those copies are byte-identical to the fallback pickWatchdogProfile
already uses, so shipping them only makes `configured` always truthy,
which permanently disables the promotion gate (!configured) and pins
resumed cron/explicit-timeout turns to the 180s resume no-output ceiling
instead of the 600s fresh ceiling.
Removing the blocks lets `configured` be undefined, restoring the
promotion gate. No user-config path is affected: reliability.watchdog
is not exposed in the config schema, the descriptor is the sole source,
and pickWatchdogProfile is the only runtime reader. The codex backend
never shipped the block, so this aligns the three backends.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(cli-runner): add descriptor-through-resolver watchdog proof (#125045)
Drive the real shipped Anthropic/Gemini CLI backend descriptor config through
the production resolveCliNoOutputTimeoutMs resolver to prove the resumed-cron
promotion is live post-fix. Pre-fix the descriptor shipped byte-identical
resume defaults, so configured was truthy and the !configured promotion gate
was dead, pinning resumed cron turns to the 180s resume ceiling (180000).
Post-fix the block is gone and the resolver returns the promoted fresh budget
(480000 = 600000 * 0.8).
resolveCliNoOutputTimeoutMs is re-exported through the test-only
openclaw/plugin-sdk/test-fixtures subpath (excluded from published dist), so
extension tests can drive the real descriptor through the real resolver without
crossing the extension/core boundary.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(anthropic): split watchdog promotion proof into its own file
Move the descriptor-shape and descriptor→resolver real-behavior proof
tests out of cli-shared.test.ts into cli-watchdog-promotion.test.ts.
cli-shared.test.ts exceeded the extensions max-lines budget (1000
non-blank/non-comment lines) once the proof tests landed; the focused
file keeps the same test names and coverage while staying under the
budget. No production change.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(cli-runner): restore inherited resume watchdog promotion
Validate bundled plugin descriptors through their public setup entries and keep custom watchdog contracts intact.
Co-authored-by: ruel225 <ruel225@users.noreply.github.com>
* chore(cli-runner): align conflicting provider owner with main
Co-authored-by: ruel225 <ruel225@users.noreply.github.com>
* fix(cli-runner): complete inherited resume watchdog promotion
Co-authored-by: ruel225 <ruel225@users.noreply.github.com>
* test(cli): keep watchdog regressions in their owning plugins
Keep Anthropic and Google descriptor assertions inside their plugin-owned registration suites, preserve generic resumed/custom watchdog coverage in its core owner, and remove the cross-plugin core test rejected by architecture CI.
Co-authored-by: ruel225 <ruel225@users.noreply.github.com>
---------
Co-authored-by: ruel225 <ruel225@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Seed the SDK-owned version before environment fingerprinting so resumed turns retain the live query and prompt cache.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(agents): preserve CLI session binding on format-class failover
shouldClearFailedCliSessionBinding cleared the stored CLI session
binding for every FailoverError, including format-class failures
(output limit exceeded, parser error, unsupported image input). A
format-class failover means the stream could not be read, not that
the CLI session on disk is invalid — clearing the binding silently
lost the conversation context on the next turn.
Narrow the condition to only session-invalidating failover reasons
(session_expired, auth, auth_permanent) using a whitelist so new
reasons default to preserving the binding.
Fixes#128698
* fix(agents): preserve valid CLI session bindings
* fix(agents): retain CLI binding across format recovery
* fix(agents): scope fresh CLI recovery by backend
* docs(plugins): document CLI recovery policy
---------
Co-authored-by: Vincent Koc <vincentkoc@users.noreply.github.com>
Route Claude Agent SDK AskUserQuestion through OpenClaw's shared structured-input flow across the Control UI and existing channel fallback surfaces.
Fixes#81099.
* refactor(anthropic): explore official Claude Agent SDK runtime
* refactor(anthropic): replace handwritten Claude sessions with SDK
* refactor(anthropic): collapse SDK live-session ownership
* refactor(anthropic): simplify SDK ownership and preserve live skills
* fix(anthropic): fence cancelled SDK runs before process startup
* fix(anthropic): harden SDK approvals, lifecycle, and packaging
* refactor(anthropic): own SDK process trees and streamline runtime
* fix(anthropic): repair rebased packaging and legacy test fixtures
Adds a generic plugin-declared selectable-context-window surface mirroring thinkingLevels: ModelCatalogEntry.contextWindows + contextWindowDefault through catalog normalization and the gateway protocol, session validation on sessions.create/patch, and a 200K/1M switch inside the Control UI model picker for Claude CLI 5-series models. The Anthropic plugin owns the option mapping: explicit 1m → `[1m]` argv suffix, 200k → bare id + CLAUDE_CODE_DISABLE_1M_CONTEXT=1, omitted → bare id (shipped default argv). Run budgets follow the selection on both CLI and native paths, so a 200K session gets a matching auto-compact window instead of a silent 1M budget.
Review fixes landed in this PR: run-owner prepared-fact plumbing so ordinary replies honor the selection; atomic catalog overlay merge and normalization for the options/default tuple; one-owner tuple reads in the picker; sessions.create key-presence patch semantics; native-run budget capping.
Feature direction and in-picker switch shape by @obviyus (maintainer review).
* refactor(anthropic): split session-catalog into concept modules
Follow the #124178 sibling seam pattern while preserving behavior. Remove the max-lines suppression and baseline entry after the split.
* refactor(anthropic): own record caches in session-catalog-discovery
The record-shaped caches (catalogDiscoveryCache, claudeSessionScanCache,
their entry types, bounds, and TTLs) are consumed only by discovery; moving
them out of scan removes the scan->discovery type-import edge flagged by the
madge topology gate and leaves scan as record-agnostic fs primitives.
* fix: keep claude-cli prompt-cache prefix stable across turns
Claude CLI has no cache_control breakpoint, so mashed per-turn system
prompts rewrote the native prefix and burned cache hits on follow-ups.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(cli): scope Claude prompt cache suffix
* docs: scope Claude CLI cache guidance
* test(cli): cover Claude cache prompt modes
* fix: gate Claude CLI prompt cache flag
* docs: clarify Claude CLI cache flag gate
* fix: preserve Claude CLI system prompt roles
* fix(claude-cli): close cache flag compatibility gaps
* fix(claude-cli): reject prerelease cache flag versions
---------
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor(session-catalog): unify adoption coordination
* refactor(codex): split session catalog modules
* fix(anthropic): narrow adopted history for import
The coordinator migration hoisted history to an optional outer binding;
afterCreate needs the definite array from the create scope.
Also drop the retired session-catalog max-lines ratchet entry.
* fix(sessions): isolated gateways no longer inherit HOME external session catalogs
A gateway on isolated state (custom OPENCLAW_STATE_DIR/CONFIG_PATH/OPENCLAW_HOME,
relocated home, or any named profile) listed, read, continued, archived, and
reopened the operator's real Claude Code/Codex/OpenCode/Pi sessions from the
process HOME. External catalogs now require the default install identity for
process-HOME scans: every catalog verb receives the isolation policy and rejects
HOME-fallback local targets, unknown providers fail closed unless they declare
supportsProcessHomeIsolation, and one structured warning records the skip.
Paired-node hosts and explicitly rooted stores (CLAUDE_CONFIG_DIR, CODEX_HOME,
OPENCODE_DB, Pi session dirs) keep working; default-identity gateways are
unchanged.
* fix(sessions): inject catalog HOME-isolation fact at registry construction
* chore(sdk): regenerate plugin API baselines after rebase
* chore(sdk): regenerate plugin API baselines after rebase
* 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.
* perf(plugins): declare doctor contract surfaces
* perf(doctor): slim migration import closures
* perf(plugins): narrow doctor declaration record surface and wire owner-test lane
Registry records carry only the doctorContract declaration instead of the whole
parsed manifest, and check:changed now selects the src/plugins-owned declaration
honesty and closure-guard tests for extension module/manifest changes so
cross-lane drift cannot pass PR classification.
* fix(doctor): keep control-plane dist imports require-safe
Keep doctor and channel control-plane chunks off exec-class dependencies, and enforce native require(esm) loading during postbuild.
* chore(plugin-sdk): regenerate API baseline
* chore(plugin-sdk): sync export ordering
* fix(plugins): satisfy doctor contract CI boundaries
* perf(doctor): make qqbot doctor closure dependency-light
qqbot was the last plugin above 5s in doctor state-migration enumeration
(~8s under tsx/jiti). The cost was not the state-key builder (already a
leaf): its doctor closure value-imported the runtime-doctor SDK barrel,
whose plugin-state-store/state-db re-exports pull kysely (~330 modules),
plus security-runtime for one fileExists (~200 modules), all resolved
per-module by jiti during enumeration.
Split the migration-define helpers and light re-exports into a new
private-local plugin-sdk/runtime-doctor-migrations subpath; runtime-doctor
re-exports it so its public surface is byte-identical (API baseline hash
unchanged). qqbot's doctor-contract and state-migrations now import only
the light subpath, swapping fileExists for the equivalent async
legacyStateFileExists already in the closure.
qqbot enumeration: ~8.0s/531 modules -> ~0.25s/18 modules.
* chore(plugin-sdk): drop private-local subpath from API baseline
runtime-doctor-migrations is private-local-only; the baseline tracks public
modules, and the earlier line was generated before the classification.
* fix(plugins): register runtime-doctor-migrations boundary paths
The private-local subpath list feeds the extension package boundary map;
the shared paths config and xai's derived overrides must carry the same
entry or the boundary contract test fails.