restrict-plus-operands (Buffer + string) and no-promise-executor-return
tripped the lint shards on every PR since #101783 landed; scoped fixes
only, no behavior change.
Long-running Telegram senders leaked HTTP transports: the client-options cache in extensions/telegram/src/send.ts created an owned undici dispatcher per account/network entry but evicted entries without closing it. Cache entries now own their transport; eviction retires the entry and closes the transport once the operation-level lease releases, so cache pressure never aborts an in-flight, retrying, or still-preparing send. Includes a real-socket e2e regression against a local Bot API server.
Co-authored-by: zhangguiping-xydt <zhangguiping-xydt@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* feat(browser): import Chrome-family system-profile cookies into managed profiles
Import cookies from a real Chrome/Brave/Edge/Chromium system profile (macOS)
into a fresh OpenClaw-managed browser profile so the agent can browse as the
signed-in user. Reads the source Cookies DB via a coherent VACUUM INTO snapshot,
decrypts v10 AES-128-CBC values with the Safe Storage Keychain key (one Touch ID
consent), maps rows to Playwright cookies (FILETIME expiry, SameSite, M124+
domain-hash prefix strip, CHIPS skipped), and best-effort injects them via
addCookies into a mock-keychain profile so they persist without further prompts.
Decrypted values are never logged or returned.
Exposed as agent tool action=importprofile, CLI system-profiles/import-profile,
and POST /profiles/import; action=profiles surfaces importable systemProfiles.
Listing and import are pinned host-local at every surface (gateway, browser
tool, node proxy) since they read the local Keychain and Chrome profiles.
Malformed domain filters fail closed via a shared validator. Gated by
browser.allowSystemProfileImport (default on). Imports cookies only.
* fix(browser): satisfy CI lint (OpenClaw temp dir, Unicode control-char class)
Use resolvePreferredOpenClawTmpDir() instead of os.tmpdir() for the cookie DB
snapshot (messaging/channel runtime tmpdir guard), and match control characters
via the Unicode \p{Cc} class instead of a literal control-char range so the
CLI table sanitizer passes the no-control-regex lint.
* fix(feishu): keep streaming card snapshots authoritative
Co-authored-by: Jun Ma <hpumajunhappy@163.com>
* refactor(feishu): use current snapshot as retry source
* fix(feishu): validate CardKit response bodies
* fix(feishu): keep close summaries accepted
* test(feishu): simplify close rejection state proof
* test(feishu): match normalized close summary
---------
Co-authored-by: Jun Ma <hpumajunhappy@163.com>
* fix(chutes): redact OAuth error response body in token exchange and refresh
Replace readResponseTextLimited + raw body in error message with
extractProviderErrorDetail for bounded, redacted structured error detail.
Ref: #102953
* fix(chutes): update test assertions for extractProviderErrorDetail message format
* fix(chutes): remove unused readResponseTextLimited and CHUTES_OAUTH_ERROR_BODY_LIMIT_BYTES
* fix(chutes): normalize OAuth HTTP failures
* test(chutes): assert redaction without fixed mask
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(anthropic): delegate adaptive CLI effort
Strip static --effort args for adaptive runs so Claude Code resolves effort from its environment, settings, and model default. Preserve configured effort for off or absent thinking and replace it only for concrete OpenClaw levels.
Fixes#103245
Co-authored-by: Dan Korotin <korotin.daniil@gmail.com>
* fix(anthropic): make effort dispatch exhaustive
---------
Co-authored-by: Dan Korotin <korotin.daniil@gmail.com>
* feat(agents): derive a provider-declared default utility model when unset
When agents.defaults.utilityModel is not set, utility tasks (titles, progress
narration) now use the primary provider's declared small model
(modelCatalog.providers.<id>.defaultUtilityModel: OpenAI -> gpt-5.6-luna,
Anthropic -> claude-haiku-4-5). Auth is inherent because derivation follows
the agent's primary provider. Setting utilityModel to an empty string
disables utility routing entirely; narration turns on automatically when a
default resolves and stays off otherwise.
Formatting/lint/tests verified on Testbox (oxfmt, oxlint, plugins:inventory,
docs:map, import-cycles, check:test-types, 4 test files).
* fix(ai): drop the temperature parameter for models that reject it
The GPT-5.6 family 400s on temperature via the Responses API (live-verified:
gpt-5.6-luna/-terra reject it; gpt-5.5 and gpt-5.4-mini/nano accept it).
supportsOpenAITemperature gates all three OpenAI payload builders, with a
catalog compat override (compat.supportsTemperature) declared for the 5.6
family in the openai manifest. Without this, utility tasks (titles,
narration) would fail once gpt-5.6-luna becomes the derived default.
Gates on Testbox: oxfmt, oxlint, plugins:inventory, import-cycles,
check:test-types, 6 test files. Live proof on Testbox: gpt-5.6-luna and
claude-haiku-4-5 one-shot completions succeed with temperature requested.
* fix(agents): carry the primary model's auth profile onto the derived utility default
A primary like openai/gpt-5.5@work previously reached utility tasks via the
profiled fallback; the derived default shares the provider, so its trailing
auth profile carries over instead of silently switching to default
credentials (Codex review). Gates on Testbox: oxfmt, check:test-types, tests.
* docs: realign the manifest provider-fields table after adding defaultUtilityModel
* fix(signal): clean up signal-cli download temp dir on every exit path
installSignalCliFromRelease created a temp dir with fs.mkdtemp for the
download archive but never removed it. Every return path — including the
success return and the extraction-failure / binary-not-found errors — leaked
the directory plus the downloaded archive (signal-cli Linux-native archives
are ~50-130 MB). Repeated installs or retries accumulated multi-hundred-MB
temp dirs under the preferred tmp dir.
Wrap the body after mkdtemp in try/finally that recursively removes the temp
dir. The extracted binary is installed under CONFIG_DIR and is unaffected.
Co-Authored-By: Claude <noreply@anthropic.com>
* style(signal): drop unnecessary String() conversion in test spy
dir is already a string (mkdtemp return); String(dir) triggers the
no-unnecessary-type-conversion lint rule.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(signal): cover success-path temp dir cleanup with real archive
Add a success-path test that mocks the network fetch to return a real tar.gz
archive (containing a signal-cli binary) so installSignalCliFromRelease runs the
full download -> extract -> find-binary -> chmod path against real bytes, then
asserts the temp dir and downloaded archive are removed by the finally clause.
This complements the existing error-path test so both exit paths are covered.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(signal): use owned temp download workspace
* fix(signal): allow bounded native extraction
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>