Compare commits

...

14 Commits

Author SHA1 Message Date
Peter Steinberger
be8c24633a docs: consolidate 2026.4.26 changelog 2026-04-28 02:12:58 +01:00
Peter Steinberger
414b68df6f chore(release): prepare 2026.4.26 stable 2026-04-28 02:10:33 +01:00
Peter Steinberger
2c7f65e025 docs: record npm provenance in release evidence 2026-04-28 01:57:17 +01:00
Peter Steinberger
7c44230fda ci: support ref-backed telegram package e2e 2026-04-28 01:45:13 +01:00
Peter Steinberger
09d044e0f4 test: tolerate old Windows updater restart handoff 2026-04-28 00:59:29 +01:00
Peter Steinberger
a230f0f558 test: tolerate transient release validation output 2026-04-27 23:56:18 +01:00
Peter Steinberger
aed6ccf090 test: stabilize live release checks 2026-04-27 23:34:20 +01:00
Peter Steinberger
17596fc484 fix(update): restart Windows startup gateway after update 2026-04-27 23:14:17 +01:00
Peter Steinberger
42220c929a ci: record package proof in release evidence 2026-04-27 21:58:17 +01:00
Peter Steinberger
0518ff6f35 chore(release): refresh config baseline after coven removal 2026-04-27 19:54:51 +01:00
Peter Steinberger
6b97dee4c1 chore(release): refresh plugin sdk api baseline 2026-04-27 19:50:53 +01:00
Peter Steinberger
4623bba650 chore(release): refresh config docs baseline 2026-04-27 19:50:53 +01:00
Peter Steinberger
f02ced0fab chore(release): refresh bundled channel metadata 2026-04-27 19:50:53 +01:00
Peter Steinberger
49aa1d07b0 chore(release): prepare 2026.4.26 beta 1 2026-04-27 19:50:53 +01:00
18 changed files with 359 additions and 137 deletions

View File

@@ -324,12 +324,14 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
- install/update smoke against the published beta channel
- Docker install/update coverage that exercises the published beta package
- published npm Telegram proof: dispatch Actions > `NPM Telegram Beta E2E`
from `main` with `package_spec=openclaw@<beta-version>` and
`provider_mode=mock-openai`, and require success. This workflow is
from `main` with `source=npm`, `package_spec=openclaw@<beta-version>`,
and `provider_mode=mock-openai`, and require success. Before publishing,
use the same workflow with `source=ref` and `package_ref=<branch-or-sha>`
for focused tarball-backed Telegram preflight. This workflow is
maintainer-dispatched and intentionally has no `npm-release` approval gate;
`qa-live-shared` only supplies the shared QA secrets. This is the default
button path for installed-package onboarding, Telegram setup, and real
Telegram E2E against the published npm package.
`qa-live-shared` only supplies the shared QA secrets. The npm source is the
default button path for installed-package onboarding, Telegram setup, and
real Telegram E2E against the exact published npm package.
Use the local `pnpm test:docker:npm-telegram-live` lane with the matching
`OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC` and Convex CI env only as a fallback
or debugging path.
@@ -380,6 +382,27 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
retesting.
- If any required build, packaging step, or release workflow is red, do not say the release is ready.
## Record release evidence with npm provenance
- Every release validation evidence report should identify whether it matches a
published npm package. When dispatching `.github/workflows/full-release-validation.yml`
for a package that is already published or expected to be published before
evidence is finalized, pass `evidence_package_spec=openclaw@<version>`.
- When the post-publish Telegram npm lane is part of the same full validation,
also pass `npm_telegram_package_spec=openclaw@<version>` so the validation
proves the exact registry package, not only a branch/ref tarball.
- If a full validation was started before the npm package existed, regenerate
the private evidence after publish with
`openclaw/releases-private/.github/workflows/openclaw-release-evidence-from-full-validation.yml`
and pass `package_spec=openclaw@<version>`, the original
`full_validation_run_id`, and a human release id such as `YYYY.M.D`.
- Use SHA evidence ids for immutable debugging, but also create/update the
human stable evidence bucket (`evidence/YYYY.M.D/`) after stable publish so
maintainers can find the final npm/release proof quickly.
- Do not claim npm proof from a ref-backed or local tarball-backed run. Label
those as pre-publish package/tarball proof, and keep the npm registry proof
tied to `source=npm` or `package_spec=openclaw@<published-version>`.
## Use the right auth flow
- OpenClaw publish uses GitHub trusted publishing.
@@ -610,6 +633,11 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
`appcast.xml` artifact and do not update the shared production feed unless a
separate beta feed exists.
32. After publish, verify npm and the attached release artifacts.
33. After any beta or stable npm publish, ensure the private release evidence
report includes `package_spec=openclaw@<published-version>` and shows the
npm package match. If the original full validation omitted the package spec,
rerun the private evidence generation workflow with the same
`full_validation_run_id` and the published package spec.
## GHSA advisory work

View File

@@ -31,6 +31,11 @@ on:
required: false
default: ""
type: string
evidence_package_spec:
description: Optional published package spec to prove in the private release evidence report
required: false
default: ""
type: string
npm_telegram_provider_mode:
description: Provider mode for the optional post-publish Telegram E2E lane
required: false
@@ -83,6 +88,7 @@ jobs:
TARGET_SHA: ${{ steps.resolve.outputs.sha }}
CHILD_WORKFLOW_REF: ${{ github.ref_name }}
NPM_TELEGRAM_PACKAGE_SPEC: ${{ inputs.npm_telegram_package_spec }}
EVIDENCE_PACKAGE_SPEC: ${{ inputs.evidence_package_spec }}
run: |
{
echo "## Full release validation"
@@ -92,11 +98,15 @@ jobs:
echo "- Child workflow ref: \`${CHILD_WORKFLOW_REF}\`"
echo "- Normal CI: \`CI\` with \`target_ref=${TARGET_SHA}\`"
echo "- Release/live/Docker/package/QA: \`OpenClaw Release Checks\`"
echo "- Pre-publish Telegram package E2E: included through \`OpenClaw Release Checks\` Package Acceptance for \`${TARGET_SHA}\`"
if [[ -n "${NPM_TELEGRAM_PACKAGE_SPEC// }" ]]; then
echo "- Post-publish Telegram E2E: \`${NPM_TELEGRAM_PACKAGE_SPEC}\`"
else
echo "- Post-publish Telegram E2E: skipped because no published package spec was provided"
fi
if [[ -n "${EVIDENCE_PACKAGE_SPEC// }" ]]; then
echo "- Private evidence package proof: \`${EVIDENCE_PACKAGE_SPEC}\`"
fi
} >> "$GITHUB_STEP_SUMMARY"
normal_ci:
@@ -352,7 +362,7 @@ jobs:
env:
RELEASE_PRIVATE_DISPATCH_TOKEN: ${{ secrets.OPENCLAW_RELEASES_PRIVATE_DISPATCH_TOKEN }}
TARGET_REF: ${{ inputs.ref }}
PACKAGE_SPEC: ${{ inputs.npm_telegram_package_spec }}
PACKAGE_SPEC: ${{ inputs.evidence_package_spec || inputs.npm_telegram_package_spec }}
GITHUB_RUN_ID_VALUE: ${{ github.run_id }}
run: |
set -euo pipefail

View File

@@ -5,9 +5,44 @@ on:
inputs:
package_spec:
description: Published OpenClaw package spec to test when no artifact is supplied
required: true
required: false
default: openclaw@beta
type: string
source:
description: Package candidate source when no package-under-test artifact is supplied
required: true
default: npm
type: choice
options:
- npm
- ref
- url
- artifact
package_ref:
description: Trusted package source ref when source=ref
required: false
default: main
type: string
package_url:
description: HTTPS .tgz URL when source=url
required: false
default: ""
type: string
package_sha256:
description: Expected package SHA-256 for source=url or source=artifact
required: false
default: ""
type: string
artifact_run_id:
description: GitHub Actions run id when source=artifact
required: false
default: ""
type: string
artifact_name:
description: Artifact name containing one .tgz when source=artifact
required: false
default: package-under-test
type: string
package_label:
description: Optional display label for an artifact-backed package candidate
required: false
@@ -39,7 +74,38 @@ on:
inputs:
package_spec:
description: Published OpenClaw package spec to test when no artifact is supplied
required: true
required: false
default: openclaw@beta
type: string
source:
description: "Package candidate source when no package-under-test artifact is supplied: npm, ref, url, or artifact"
required: false
default: npm
type: string
package_ref:
description: Trusted package source ref when source=ref
required: false
default: main
type: string
package_url:
description: HTTPS .tgz URL when source=url
required: false
default: ""
type: string
package_sha256:
description: Expected package SHA-256 for source=url or source=artifact
required: false
default: ""
type: string
artifact_run_id:
description: GitHub Actions run id when source=artifact
required: false
default: ""
type: string
artifact_name:
description: Artifact name containing one .tgz when source=artifact
required: false
default: package-under-test
type: string
package_artifact_name:
description: Optional package-under-test artifact from the current workflow run
@@ -75,6 +141,7 @@ on:
required: false
permissions:
actions: read
contents: read
concurrency:
@@ -93,6 +160,7 @@ jobs:
timeout-minutes: 60
environment: qa-live-shared
permissions:
actions: read
contents: read
env:
DOCKER_BUILD_SUMMARY: "false"
@@ -102,7 +170,7 @@ jobs:
uses: actions/checkout@v6
with:
ref: ${{ inputs.harness_ref || github.sha }}
fetch-depth: 1
fetch-depth: 0
- name: Set up Blacksmith Docker Builder
uses: useblacksmith/setup-docker-builder@ac083cc84672d01c60d5e8561d0a939b697de542 # v1
@@ -131,6 +199,12 @@ jobs:
- name: Validate inputs and secrets
env:
PACKAGE_SPEC: ${{ inputs.package_spec }}
SOURCE: ${{ inputs.source }}
PACKAGE_REF: ${{ inputs.package_ref }}
PACKAGE_URL: ${{ inputs.package_url }}
PACKAGE_SHA256: ${{ inputs.package_sha256 }}
ARTIFACT_RUN_ID: ${{ inputs.artifact_run_id }}
ARTIFACT_NAME: ${{ inputs.artifact_name }}
PACKAGE_ARTIFACT_NAME: ${{ inputs.package_artifact_name || '' }}
PROVIDER_MODE: ${{ inputs.provider_mode }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
@@ -140,12 +214,36 @@ jobs:
run: |
set -euo pipefail
if [[ -z "${PACKAGE_ARTIFACT_NAME// }" ]]; then
case "${SOURCE}" in
npm | ref | url | artifact) ;;
*)
echo "source must be npm, ref, url, or artifact; got: ${SOURCE}" >&2
exit 1
;;
esac
if [[ -z "${PACKAGE_ARTIFACT_NAME// }" && "${SOURCE}" == "npm" ]]; then
if [[ ! "${PACKAGE_SPEC}" =~ ^openclaw@(beta|latest|[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*(-[1-9][0-9]*|-beta\.[1-9][0-9]*)?)$ ]]; then
echo "package_spec must be openclaw@beta, openclaw@latest, or an exact OpenClaw release version; got: ${PACKAGE_SPEC}" >&2
exit 1
fi
fi
if [[ -z "${PACKAGE_ARTIFACT_NAME// }" && "${SOURCE}" == "ref" && -z "${PACKAGE_REF// }" ]]; then
echo "package_ref is required when source=ref." >&2
exit 1
fi
if [[ -z "${PACKAGE_ARTIFACT_NAME// }" && "${SOURCE}" == "url" ]]; then
if [[ -z "${PACKAGE_URL// }" || -z "${PACKAGE_SHA256// }" ]]; then
echo "package_url and package_sha256 are required when source=url." >&2
exit 1
fi
fi
if [[ -z "${PACKAGE_ARTIFACT_NAME// }" && "${SOURCE}" == "artifact" ]]; then
if [[ -z "${ARTIFACT_RUN_ID// }" || -z "${ARTIFACT_NAME// }" ]]; then
echo "artifact_run_id and artifact_name are required when source=artifact." >&2
exit 1
fi
fi
case "${PROVIDER_MODE}" in
mock-openai | live-frontier) ;;
*)
@@ -175,6 +273,46 @@ jobs:
name: ${{ inputs.package_artifact_name }}
path: .artifacts/telegram-package-under-test
- name: Download package artifact input
if: inputs.package_artifact_name == '' && inputs.source == 'artifact'
env:
GH_TOKEN: ${{ github.token }}
ARTIFACT_RUN_ID: ${{ inputs.artifact_run_id }}
ARTIFACT_NAME: ${{ inputs.artifact_name }}
shell: bash
run: |
set -euo pipefail
mkdir -p .artifacts/telegram-package-input
gh run download "$ARTIFACT_RUN_ID" -n "$ARTIFACT_NAME" -D .artifacts/telegram-package-input
- name: Resolve package-under-test candidate
if: inputs.package_artifact_name == '' && inputs.source != 'npm'
id: resolve_candidate
env:
SOURCE: ${{ inputs.source }}
PACKAGE_REF: ${{ inputs.package_ref }}
PACKAGE_SPEC: ${{ inputs.package_spec }}
PACKAGE_URL: ${{ inputs.package_url }}
PACKAGE_SHA256: ${{ inputs.package_sha256 }}
shell: bash
run: |
set -euo pipefail
artifact_dir="."
if [[ "${SOURCE}" == "artifact" ]]; then
artifact_dir=".artifacts/telegram-package-input"
fi
node scripts/resolve-openclaw-package-candidate.mjs \
--source "$SOURCE" \
--package-ref "$PACKAGE_REF" \
--package-spec "$PACKAGE_SPEC" \
--package-url "$PACKAGE_URL" \
--package-sha256 "$PACKAGE_SHA256" \
--artifact-dir "$artifact_dir" \
--output-dir .artifacts/telegram-package-under-test \
--output-name openclaw-current.tgz \
--metadata .artifacts/telegram-package-under-test/package-candidate.json \
--github-output "$GITHUB_OUTPUT"
- name: Run package Telegram E2E
id: run_lane
shell: bash
@@ -200,10 +338,15 @@ jobs:
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
export OPENCLAW_NPM_TELEGRAM_OUTPUT_DIR="${output_dir}"
if [[ -n "${PACKAGE_ARTIFACT_NAME// }" ]]; then
mapfile -t package_tgzs < <(find .artifacts/telegram-package-under-test -type f -name "*.tgz" | sort)
package_dir=".artifacts/telegram-package-under-test"
if [[ -d "${package_dir}" ]]; then
mapfile -t package_tgzs < <(find "${package_dir}" -type f -name "*.tgz" | sort)
else
package_tgzs=()
fi
if [[ "${#package_tgzs[@]}" -gt 0 ]]; then
if [[ "${#package_tgzs[@]}" -ne 1 ]]; then
echo "package artifact ${PACKAGE_ARTIFACT_NAME} must contain exactly one .tgz; found ${#package_tgzs[@]}" >&2
echo "package-under-test candidate must contain exactly one .tgz; found ${#package_tgzs[@]}" >&2
exit 1
fi
export OPENCLAW_NPM_TELEGRAM_PACKAGE_TGZ="${package_tgzs[0]}"

View File

@@ -4,48 +4,37 @@ Docs: https://docs.openclaw.ai
## Unreleased
### Changes
- Plugins/models: wire manifest `modelCatalog.aliases` and `modelCatalog.suppressions` into model-catalog planning and built-in model suppression, with OpenAI stale Spark suppression now declared in the plugin manifest before runtime fallback. Thanks @shakkernerd.
- Channels/Yuanbao: register the Tencent Yuanbao external channel plugin (`openclaw-plugin-yuanbao`) in the official channel catalog, contract suites, and community plugin docs, with a new `docs/channels/yuanbao.md` quick-start guide for WebSocket bot DMs and group chats. (#72756) Thanks @loongfay.
- Channels/QQBot: add full group chat support (history tracking, @-mention gating, activation modes, per-group config, FIFO message queue with deliver debounce), C2C `stream_messages` streaming with a `StreamingController` lifecycle manager, unified `sendMedia` with chunked upload for large files, and refactor the engine into pipeline stages, focused outbound submodules, builtin slash-command modules, and explicit DI ports via `createEngineAdapters()`. (#70624) Thanks @cxyhhhhh.
- Gateway/runtime: reuse the current plugin metadata snapshot for provider discovery so repeated model-provider discovery avoids rebuilding plugin manifest metadata. Thanks @shakkernerd.
- Gateway/startup: pass the plugin metadata snapshot from config validation into plugin bootstrap so startup reuses one manifest product instead of rebuilding plugin metadata. Thanks @shakkernerd.
### Fixes
- Agents/LSP: terminate bundled stdio LSP process trees during runtime disposal and Gateway shutdown, so nested children such as `tsserver` do not survive stop or restart. Fixes #72357. Thanks @ai-hpc and @bittoby.
## 2026.4.26
### Changes
- Channels/QQBot: add full group chat support (history tracking, @-mention gating, activation modes, per-group config, FIFO message queue with deliver debounce), C2C `stream_messages` streaming with a `StreamingController` lifecycle manager, unified `sendMedia` with chunked upload for large files, and refactor the engine into pipeline stages, focused outbound submodules, builtin slash-command modules, and explicit DI ports via `createEngineAdapters()`. (#70624) Thanks @cxyhhhhh.
- Channels/Yuanbao: register the Tencent Yuanbao external channel plugin (`openclaw-plugin-yuanbao`) in the official channel catalog, contract suites, and community plugin docs, with a new `docs/channels/yuanbao.md` quick-start guide for WebSocket bot DMs and group chats. (#72756) Thanks @loongfay.
- Control UI/Talk: add a generic browser realtime transport contract, Google Live browser Talk sessions with constrained ephemeral tokens, and a Gateway relay for backend-only realtime voice plugins. Thanks @VACInc.
- CLI/models: route provider-filtered model listing through an explicit source plan so user config, installed manifest rows, Provider Index previews, and scoped runtime fallbacks keep a stable authority order without adding another catalog cache. Thanks @shakkernerd.
- Providers: add Cerebras as a bundled plugin with onboarding, static model catalog, docs, and manifest-owned endpoint metadata.
- Memory/OpenAI-compatible: add optional `memorySearch.inputType`, `queryInputType`, and `documentInputType` config for asymmetric embedding endpoints, including direct query embeddings and provider batch indexing. Carries forward #63313 and #60727. Thanks @HOYALIM and @prospect1314521.
- Ollama/memory: add model-specific retrieval query prefixes for `nomic-embed-text`, `qwen3-embedding`, and `mxbai-embed-large` memory-search queries while leaving document batches unchanged. Carries forward #45013. Thanks @laolin5564.
- Plugins/providers: move pre-runtime model-id normalization, provider endpoint host metadata, and OpenAI-compatible request-family hints into plugin manifests so core no longer carries bundled-provider routing tables.
- Plugins/providers: move pre-runtime model-id normalization, endpoint host metadata, OpenAI-compatible request-family hints, model-catalog aliases/suppressions, OpenAI stale Spark suppression, and reusable startup metadata snapshots into plugin manifests so core no longer carries bundled-provider routing tables or repeated manifest rebuilds. Thanks @shakkernerd.
- Plugins/config: deprecate direct plugin config load/write helpers in favor of passed runtime snapshots plus transactional mutation helpers with explicit restart follow-up policy, scanner guardrails, runtime warnings, and revision-based cache invalidation.
- Plugins/install: allow `OPENCLAW_PLUGIN_STAGE_DIR` to contain layered runtime-dependency roots, resolving read-only preinstalled deps before installing missing deps into the final writable root. Fixes #72396. Thanks @liorb-mountapps.
- Control UI: add a raw config pending-changes diff panel that parses JSON5, redacts sensitive values until reveal, and avoids fake raw-edit callbacks when opening the panel. Refs #39831; supersedes #48621 and #46654. Thanks @JiajunBernoulli and @BunsDev.
- Control UI: polish the quick settings dashboard grid so common cards align across desktop, tablet, and mobile layouts without wasting horizontal space. Thanks @BunsDev.
- Matrix/E2EE: add `openclaw matrix encryption setup` to enable Matrix encryption, bootstrap recovery, and print verification status from one setup flow. Thanks @gumadeiras.
- Agents/compaction: add an opt-in `agents.defaults.compaction.maxActiveTranscriptBytes` preflight trigger that runs normal local compaction when the active JSONL grows too large, requiring transcript rotation so successful compaction moves future turns onto a smaller successor file instead of raw byte-splitting history. Thanks @vincentkoc.
- CLI/migration: add a bundled Claude importer that previews and applies Claude Code and Claude Desktop instructions, MCP servers, skills, command prompts, and safe archive/manual-review state. Thanks @vincentkoc.
- CLI/migration: add `openclaw migrate` with plan, dry-run, JSON, pre-migration backup, onboarding detection, archive-only report copies, and a bundled Hermes importer for configuration, memory/plugin hints, model providers, MCP servers, skills, and supported credentials. Thanks @NousResearch.
- CLI/migration: add `openclaw migrate` with plan, dry-run, JSON, pre-migration backup, onboarding detection, archive-only reports, a Claude Code/Desktop importer, and a Hermes importer for configuration, memory/plugin hints, model providers, MCP servers, skills, commands, and supported credentials. Thanks @vincentkoc and @NousResearch.
### Fixes
- Agents/LSP: terminate bundled stdio LSP process trees during runtime disposal and Gateway shutdown, so nested children such as `tsserver` do not survive stop or restart. Fixes #72357. Thanks @ai-hpc and @bittoby.
- Gateway/device tokens: stop echoing rotated bearer tokens from shared/admin `device.token.rotate` responses while preserving the same-device token handoff needed by token-only clients before reconnect. (#66773) Thanks @MoerAI.
- Control UI/Talk: keep Google Live browser sessions on the WebSocket transport instead of falling back to WebRTC, validate browser Google Live WebSocket endpoints, cap Gateway relay sessions per browser connection, and remove stale browser-native voice buttons that did not use the configured Talk/TTS provider. Thanks @BunsDev.
- Gateway/startup: reuse config snapshot plugin manifests for startup auto-enable before plugin bootstrap plans plugin loading. Thanks @shakkernerd.
- Gateway/startup: reuse config snapshot plugin manifests for startup auto-enable, config validation, and plugin bootstrap planning, including authored source config and disabled setup-probe handling, so restrictive allowlists avoid duplicate manifest/config passes during boot. Thanks @shakkernerd.
- Agents/subagents: enforce `subagents.allowAgents` for explicit same-agent `sessions_spawn(agentId=...)` calls instead of auto-allowing requester self-targets. Fixes #72827. Thanks @oiGaDio.
- ACP/sessions_spawn: let explicit `sessions_spawn(runtime="acp")` bootstrap turns run while `acp.dispatch.enabled=false` still blocks automatic ACP thread dispatch. Fixes #63591. Thanks @moeedahmed.
- CLI/update: install npm global updates into a verified temporary prefix before swapping the package tree into place, preventing mixed old/new installs and stale packaged files from breaking `openclaw update` verification. Thanks @shakkernerd.
- Gateway: skip CLI startup self-respawn for foreground gateway runs so low-memory Linux/Node 24 hosts start through the same path as direct `dist/index.js` without hanging before logs. Fixes #72720. Thanks @sign-2025.
- Google Meet: grant Meet media permissions through browser control and pin local Chrome audio defaults to `BlackHole 2ch`, so joined agents no longer show `Permission needed` or use macOS default audio devices. Thanks @DougButdorf.
- Google Meet: route local Chrome joins through OpenClaw browser control instead of raw default Chrome, so agents use the configured OpenClaw browser profile when opening Meet. Thanks @oromeis.
- Google Meet: route local Chrome joins through OpenClaw browser control, grant Meet media permissions, pin local Chrome audio defaults to `BlackHole 2ch`, and use the configured OpenClaw browser profile so joined agents no longer show `Permission needed` or use raw/default Chrome state. Thanks @DougButdorf and @oromeis.
- Plugins/discovery: follow symlinked plugin directories in global and workspace plugin roots while keeping broken links ignored and existing package safety checks in place. Fixes #36754; carries forward #72695 and #63206. Thanks @Quackstro, @ming1523, and @xsfX20.
- Plugins/install: skip test files and directories during install security scans while still force-scanning declared runtime entrypoints, so packaged test mocks no longer block plugin installs. Fixes #66840; carries forward #67050. Thanks @saurabhjain1592 and @Magicray1217.
- Plugins/install: allow exact package-manager peer links back to the trusted OpenClaw host package during install security scans while continuing to block spoofed or nested escaping `node_modules` symlinks. Carries forward #70819. Thanks @fgabelmannjr.
@@ -63,8 +52,7 @@ Docs: https://docs.openclaw.ai
- Local models: default custom providers with only `baseUrl` to the Chat Completions adapter and trust loopback model requests automatically, so local OpenAI-compatible proxies receive `/v1/chat/completions` without timing out. Fixes #40024. Thanks @parachuteshe.
- Channels/message tool: surface Discord, Slack, and Mattermost `user:`/`channel:` target syntax in the shared message target schema and Discord ambiguity errors, so DM sends by numeric id stop burning retries before finding `user:<id>`. Fixes #72401. Thanks @garyd9, @hclsys, and @praveen9354.
- Agents/tools: scope tool-loop detection history to the active run when available, so scheduled heartbeat cycles no longer inherit stale repeated-call counts from previous runs. Fixes #40144. Thanks @mattbrown319.
- Agents/subagents: preserve requester delivery for completion announces when a child agent is bound to a different channel account while keeping same-channel thread completions routed to the child thread. Thanks @sfuminya.
- Agents/subagents: fail closed instead of selecting a single child thread binding when completion delivery lacks requester conversation signal. Thanks @suyua9.
- Agents/subagents: preserve requester delivery for completion announces across different channel accounts, keep same-channel thread completions routed to the child thread, and fail closed instead of guessing a child binding when requester conversation signal is missing. Thanks @sfuminya and @suyua9.
- Agents/status: persist the post-compaction token estimate from auto-compaction when providers omit usage metadata, so `/status` and session lists keep showing fresh context usage after compaction. Fixes #67667; carries forward #72822. Thanks @Jimmy-xuzimo and @skylight-9.
- Control UI: show loading, reload, and retry states when a lazy dashboard panel cannot load after an upgrade, so the Logs tab no longer appears blank on stale browser bundles. Fixes #72450. Thanks @sobergou.
- Gateway/plugins: start the Gateway in degraded mode when a single plugin entry has invalid schema config, and let `openclaw doctor --fix` quarantine that plugin config instead of crash-looping every channel. Fixes #62976 and #70371. Thanks @Doraemon-Claw and @pksidekyk.
@@ -72,8 +60,6 @@ Docs: https://docs.openclaw.ai
- Agents/reasoning: recover fully wrapped unclosed `<think>` replies that would otherwise sanitize to empty text while keeping strict stripping for closed reasoning blocks and unclosed tails after visible text. Fixes #37696; supersedes #51915. Thanks @druide67 and @okuyam2y.
- Control UI/Gateway: bind WebChat handshakes to their active socket and reject post-close server registrations, so aborted connects no longer leave zombie clients or misleading duplicate WebSocket connection logs. Fixes #72753. Thanks @LumenFromTheFuture.
- Agents/fallback: split ambiguous provider failures into `empty_response`, `no_error_details`, and `unclassified`, and add flat fallback-step fields to structured fallback logs so primary-model failures stay visible when later fallbacks also fail. Fixes #71922; refs #71744. Thanks @andyk-ms and @nikolaykazakovvs-ux.
- Gateway/startup: reuse the plugin manifest registry inside config validation so restrictive plugin allowlists avoid a duplicate manifest pass during startup. Thanks @shakkernerd.
- Gateway/startup: run plugin auto-enable from authored source config and skip disabled setup probes, avoiding runtime-default plugin allowlist writes and a second config snapshot read during startup. Thanks @shakkernerd.
- Plugins/Windows: normalize Windows absolute paths before handing bundled plugin modules to Jiti, so Feishu/Lark message sending no longer fails with unsupported `c:` ESM loader URLs. Fixes #72783. Thanks @jackychen-png.
- CLI/doctor: run bundled plugin runtime-dependency repairs through the async npm installer with spinner/line progress and heartbeat updates, so long `openclaw doctor --fix` installs no longer look hung in TTY or piped output. Fixes #72775. Thanks @dfpalhano.
- Feishu/Windows: normalize bundled channel sidecar loads before Jiti evaluates them, so Feishu outbound sends no longer fail with raw `C:` ESM loader errors on Windows. Fixes #72783. Thanks @jackychen-png.
@@ -151,19 +137,7 @@ Docs: https://docs.openclaw.ai
- Docker/setup: route Docker onboarding defaults for host-side LM Studio and Ollama through `host.docker.internal` and add the Linux host-gateway mapping to the bundled Compose file, so containerized gateways can reach local providers without using container loopback. Fixes #68684; supersedes #68702. Thanks @safrano9999 and @skolez.
- Agents/LM Studio: strip prior-turn Gemma 4 reasoning from OpenAI-compatible replay while preserving active tool-call continuation reasoning. Fixes #68704. Thanks @chip-snomo and @Kailigithub.
- LM Studio: allow interactive onboarding to leave the API key blank for unauthenticated local servers, using local synthetic auth while clearing stale LM Studio auth profiles. Fixes #66937. Thanks @olamedia.
- Plugins/startup: use a `PluginLookUpTable` during Gateway startup so channel ownership, deferred channel loading, and startup plugin IDs reuse the same installed manifest registry instead of rebuilding manifest metadata on the boot path. Thanks @shakkernerd.
- Plugins/startup: pass the Gateway `PluginLookUpTable` through plugin loading so auto-enable checks and startup-scope fallback reuse the same manifest registry instead of doing another manifest pass. Thanks @shakkernerd.
- Plugins/startup: carry the Gateway `PluginLookUpTable` into deferred channel full-runtime reloads so post-listen startup does not rebuild manifest metadata after the provisional setup-runtime load. Thanks @shakkernerd.
- Gateway/models: reuse Gateway plugin manifest metadata during the initial model-pricing refresh so pricing policies and configured plugin web-search models do not rebuild plugin lookups during startup. Thanks @shakkernerd.
- Gateway/startup: extend `OPENCLAW_GATEWAY_STARTUP_TRACE=1` with per-phase event-loop delay plus plugin lookup-table timing and count metrics for installed-index, manifest, startup-plan, and owner-map work, and include the new timing fields in startup benchmark summaries. Thanks @shakkernerd.
- Plugins/channels: resolve read-only channel command defaults from one plugin index plus manifest pass instead of reloading plugin metadata while checking candidate plugin enablement. Thanks @shakkernerd.
- Plugins/capabilities: cache manifest-derived capability provider plugin IDs per config snapshot so repeated TTS, media, realtime, memory, image, video, and music provider resolution avoids redundant manifest scans. Thanks @shakkernerd.
- Plugins/contracts: resolve runtime manifest-contract plugin owners from one plugin index plus manifest pass instead of rebuilding manifest metadata separately for all owners and enabled owners. Thanks @shakkernerd.
- Plugins/extractors: reuse one manifest registry pass while resolving bundled document and web-content extractor plugins instead of rereading manifests for compatibility and enablement filtering. Thanks @shakkernerd.
- Plugins/providers: reuse one plugin registry snapshot and manifest registry while resolving provider discovery entries instead of rebuilding manifest metadata after provider owner discovery. Thanks @shakkernerd.
- Plugins/registry: resolve lookup-table owner maps for providers, CLI backends, setup providers, command aliases, model catalogs, channel configs, and manifest contracts while preserving setup-only CLI backend ownership. Thanks @shakkernerd.
- Plugins/registry: cache repeated installed-index manifest registry fallback rebuilds behind a bounded invalidating cache so cold provider-discovery paths avoid rereading unchanged manifests. Thanks @mcaxtr.
- Plugins/web: reuse manifest records already loaded for bundled web provider candidate discovery when falling back to public artifact provider loading. Thanks @shakkernerd.
- Plugins/startup/registry: reuse a Gateway `PluginLookUpTable` and one manifest registry pass across startup plugin IDs, plugin loading, deferred channel reloads, model pricing, read-only channel defaults, capability/provider/media resolution, manifest contracts, extractors, web fallback discovery, owner maps, and cold provider-discovery caches, with new startup-trace timing/count metrics for installed-index, manifest, startup-plan, and owner-map work. Thanks @shakkernerd and @mcaxtr.
- Mattermost: keep direct-message replies top-level by suppressing reply roots for DM delivery while preserving channel and group thread roots, and derive inbound chat kind from the trusted channel lookup instead of the websocket event channel type. Carries forward #60115, #55186, #72305, and #72659; refs #59758, #59981, #59791, and #57565. Thanks @vincentkoc, @jwchmodx, and @hnykda.
- Docker: pre-create `/home/node/.openclaw` with node ownership and private permissions so first-run Docker Compose named volumes no longer fail startup with EACCES. (#48072, #63959; fixes #61279) Thanks @timoxue and @jeanibarz.
- CLI/Gateway: treat local restart probe policy closes for connect, exact `device required`, pairing, and auth failures as Gateway reachability proof without accepting empty, broad standalone token/password/scope/role, or pair-substring 1008 close reasons. Fixes #48771; carries forward #48801; related #63491. Thanks @MarsDoge and @genoooool.
@@ -188,28 +162,12 @@ Docs: https://docs.openclaw.ai
- CLI/help: treat positional `help` invocations like `openclaw channels help` as help paths for startup gating, avoiding model/auth warmup while preserving positional arguments such as `openclaw docs help`. Thanks @gumadeiras.
- Web search: route plugin-scoped web_search SecretRefs through the active runtime config snapshot so provider execution receives resolved credentials across app/runtime paths, including `plugins.entries.brave.config.webSearch.apiKey`. Fixes #68690. Thanks @VACInc.
- Voice Call: allow SecretRef-backed Twilio auth tokens and call-specific OpenAI/ElevenLabs TTS API keys through the plugin config surface. Fixes #68690. Thanks @joshavant.
- Google Meet: clean stale chrome-node realtime audio bridges by URL before rejoining, expose active node bridge inspection, and tolerate transient node input pull failures instead of dropping the Meet session. Fixes #72371. (#72372) Thanks @BsnizND.
- Google Meet: use 24 kHz PCM16 for Chrome command-pair realtime audio by default, preserve legacy 8 kHz G.711 mu-law custom command pairs, and let realtime providers negotiate the selected bridge audio format. Fixes #72525. Thanks @BsnizND.
- Google Meet: clear queued Gemini Live playback when realtime interruptions arrive, restart Chrome command-pair audio output after clears, and expose Google Live interruption/VAD config knobs for Meet and Voice Call realtime bridges. Fixes #72523. (#72524) Thanks @BsnizND.
- Google Meet: add `realtime.agentId` so live meeting consults can target a named OpenClaw agent instead of always using `main`. (#72381) Thanks @BsnizND.
- Google Meet: route stateful `google_meet` tool actions through the gateway-owned runtime so created or joined realtime sessions remain visible to status, speak, and leave after the agent turn ends. Fixes #72440. (#72441) Thanks @BsnizND.
- Google Meet/Voice Call: send Gemini Live a non-blocking consult continuation before long OpenClaw agent consults finish, then deliver the final result when idle so calls and meetings do not sit silent during tool-backed answers. (#72189) Thanks @VACInc.
- Google Meet: preserve Gemini Live function names when replying to realtime tool calls so Google SDK validation accepts the `FunctionResponse` payload. Fixes #72425. (#72426) Thanks @BsnizND.
- Google Meet/Voice Call: clean stale chrome-node realtime bridges before rejoining, expose bridge inspection, tolerate transient node input pull failures, default Chrome command-pair audio to 24 kHz PCM16 while preserving legacy 8 kHz G.711 mu-law pairs, handle Gemini Live interruptions/VAD and function-response names correctly, route stateful `google_meet` tools through the gateway runtime, support `realtime.agentId`, and send non-blocking consult continuations before long tool-backed answers finish. Fixes #72371, #72525, #72523, #72440, and #72425; (#72372, #72524, #72381, #72441, #72189, #72426) Thanks @BsnizND and @VACInc.
- Discord/media: keep incidental Markdown image badges in final replies as text unless a channel opts into Markdown-image media extraction, while preserving Telegram Markdown-image media replies and explicit `MEDIA:` attachments. Fixes #72642. Thanks @solavrc and @Bartok9.
- Matrix/E2EE: stabilize recovery and broken-device QA flows while avoiding Matrix device-cleanup sync races that could leave shutdown-time crypto work running. Thanks @gumadeiras.
- Cron: apply `cron.maxConcurrentRuns` to a dedicated `cron-nested` isolated agent-turn lane as well as cron dispatch, so parallel cron jobs no longer serialize on inner LLM execution while non-cron nested flows keep their existing lane behavior. Fixes #72707. Thanks @kagura-agent.
- Cron: report isolated runs as successful when verified cron delivery already delivered the reply, while keeping unresolved Message/Canvas tool failures fatal. Fixes #72732 and #50170; follow-up to #54188. Thanks @zNatix, @pixeldyn, and @ChickenEggRoll.
- Cron: treat isolated run-level agent failures as job errors even when no reply payload is produced, synthesizing a safe error payload so model/provider failures increment error counters and trigger failure notifications instead of clearing as successful. Fixes #43604; carries forward #43631. Thanks @SPFAdvisors.
- Cron: preserve exact `NO_REPLY` tool results from isolated jobs with empty final assistant turns as quiet successes instead of surfacing incomplete-turn errors. Fixes #68452; carries forward #68453. Thanks @anyech.
- Cron: resolve failure alerts and failure-destination announcements against `session:<id>` targets before falling back to the creator session, so jobs created from group chats can notify the targeted direct session without cross-account routing errors. Refs #62777; carries forward #68535. Thanks @slideshow-dingo and @likewen-tech.
- Discord: preserve explicit `user:` and `channel:` delivery targets through plugin routing so cron announcements and failure alerts keep their intended recipient kind. Refs #62777; carries forward #62798. Thanks @neeravmakwana.
- Cron: add `failureAlert.includeSkipped` and `openclaw cron edit --failure-alert-include-skipped` so persistently skipped jobs can alert without counting skips as execution errors or affecting retry backoff. Fixes #60846. Thanks @slideshow-dingo.
- Cron: invalidate stale pending runtime slots after live or offline `jobs.json` schedule edits, while preserving due slots for formatting-only rewrites. Fixes #27996 and #71607; carries forward #71651. Thanks @xialonglee and @fagnersouza666.
- Cron: keep legacy flat `jobs.json` rows loadable while comparing split-state schedule identities, so old cron stores do not crash before in-memory hydration can normalize them.
- Cron: start isolated agent-turn execution timeouts after the runner enters its effective execution lane, so queued cron/manual runs no longer spend their whole timeout budget before useful work begins. Fixes #41783. Thanks @ayanesakura and @Hurray0.
- Cron/Telegram: preserve direct-chat thread IDs and optional account IDs when inferring reminder delivery from Telegram direct-thread session keys. Fixes #44270; carries forward #44325, #44351, #44412, and #72657. Thanks @RunMintOn, @arkyu2077, @0xsline, and @vincentkoc.
- Cron: omit synthetic `delivery.resolved` errors from `--no-deliver` run records while preserving explicit no-deliver target traces for agent-initiated messages. Fixes #72210; carries forward #72219. Thanks @hatemclawbot-collab and @xydigit-sj.
- Cron: classify isolated runs as errors from structured embedded-run execution-denial metadata, with final-output marker fallback for `SYSTEM_RUN_DENIED`, `INVALID_REQUEST`, and approval-binding refusals, so blocked commands no longer appear green in cron history. Fixes #67172; carries forward #67186. Thanks @oc-gh-dr, @hclsys, and @1yihui.
- Cron: apply `cron.maxConcurrentRuns` to the nested isolated-agent lane, start isolated execution timeouts only after the runner enters that lane, keep legacy flat `jobs.json` rows loadable, invalidate stale pending runtime slots after schedule edits, and preserve due slots for formatting-only rewrites. Fixes #72707, #27996, #71607, and #41783; carries forward #71651. Thanks @kagura-agent, @xialonglee, @fagnersouza666, @ayanesakura, and @Hurray0.
- Cron/delivery: classify isolated successes, quiet `NO_REPLY` turns, model/provider failures, execution denials, `--no-deliver` traces, skipped-job alerts, and verified delivery outcomes correctly so cron history, retries, and failure counters reflect what actually happened. Fixes #72732, #50170, #43604, #68452, #60846, #72210, and #67172; follow-up to #54188; carries forward #43631, #68453, #72219, and #67186. Thanks @zNatix, @pixeldyn, @ChickenEggRoll, @SPFAdvisors, @anyech, @slideshow-dingo, @hatemclawbot-collab, @xydigit-sj, @oc-gh-dr, @hclsys, and @1yihui.
- Cron/routing: preserve direct Telegram thread/account IDs, explicit Discord `user:`/`channel:` delivery targets, and `session:<id>` failure-destination routing so reminders, cron announcements, and failure alerts keep the intended recipient kind across direct and group chats. Fixes #44270; refs #62777; carries forward #44325, #44351, #44412, #72657, #68535, and #62798. Thanks @RunMintOn, @arkyu2077, @0xsline, @vincentkoc, @slideshow-dingo, @likewen-tech, and @neeravmakwana.
- Subagents: keep the delegated task only in the subagent system prompt and send a short initial kickoff message, avoiding duplicate task tokens while preserving multiline task formatting. Fixes #72019; carries forward #72053. Thanks @Wizongod and @ly85206559.
- Onboarding/GitHub Copilot: add manifest-owned `--github-copilot-token` support for non-interactive setup, including env fallback, tokenRef storage in ref mode, saved-profile reuse, and current Copilot default-model wiring. Refs #50002 and supersedes #50003. Thanks @scottgl9.
- Gateway/install: add a validated `--wrapper`/`OPENCLAW_WRAPPER` service install path that persists executable LaunchAgent/systemd wrappers across forced reinstalls, updates, and doctor repairs instead of falling back to raw node/bun `ProgramArguments`. Fixes #69400. (#72445) Thanks @willtmc.
@@ -221,20 +179,7 @@ Docs: https://docs.openclaw.ai
- Exec/node: synthesize a local approval plan when a paired node advertises `system.run` without `system.run.prepare`, unblocking approval-required `host=node` exec on current macOS companion nodes while preserving remote prepare for node hosts that support it. Fixes #37591 and duplicate #66839; carries forward #69725. Thanks @soloclz.
- Memory/QMD: prefer QMD's `--mask` collection pattern flag so root memory indexing stays scoped to `MEMORY.md` instead of widening to every markdown file in the workspace. Fixes #65480; supersedes #65481 and #66259. Thanks @ccage-simp, @Bortlesboat, @seank-com, and @crazyscience.
- Memory/doctor: treat the specific `gateway timeout after ...` gateway memory probe result as inconclusive instead of reporting embeddings not ready, while preserving warnings for explicit failures. Fixes #44426; carries forward #46576 with the Greptile review feedback applied. Thanks Cengiz (@ghost).
- Gateway/memory: defer QMD startup for implicit non-default agents and scope memory runtime loading to the selected memory slot so Gateway boot and first memory recall avoid broad plugin runtime fanout. Thanks @vincentkoc.
- Gateway/startup: keep core request handlers, setup wizard, and channel runtime helpers off the boot path until the first matching request, wizard run, or channel start, reducing no-plugin Gateway ready RSS and avoidable startup imports. Thanks @vincentkoc.
- Gateway/startup: keep CLI outbound channel send dependencies as lazy request-time senders so Gateway boot no longer imports channel plugin registration just to construct default deps. Thanks @vincentkoc.
- Gateway/startup: split lightweight HTTP auth helpers away from model-override helpers so Gateway bind no longer imports model catalog selection while wiring base HTTP routes. Thanks @vincentkoc.
- Gateway/startup: lazy-load plugin HTTP route dispatch when active plugin routes exist so no-plugin Gateway boot skips plugin route runtime scope setup. Thanks @vincentkoc.
- Gateway/startup: move chat run/subscriber registries onto a lightweight state module and defer chat/session event projection until the first event so Gateway boot skips session IO imports. Thanks @vincentkoc.
- Gateway/startup: keep node session runtime on a lightweight JSON parser instead of importing gateway method validation helpers during boot. Thanks @vincentkoc.
- Gateway/startup: read embedded-run activity from a lightweight shared state module so restart deferral no longer imports the embedded runner during Gateway boot. Thanks @vincentkoc.
- Gateway/startup: defer MCP loopback server imports until Gateway shutdown so normal boot no longer loads the loopback HTTP/tool schema stack just to register close handlers. Thanks @vincentkoc.
- Gateway/startup: resolve channel runtime helpers asynchronously only when an enabled/configured channel starts, so no-channel Gateway boot skips auto-reply, media, pairing, and outbound channel helper imports. Thanks @vincentkoc.
- Gateway/startup: lazy-load HTTP auth, canvas auth, and plugin route scope helpers from their request paths so Gateway bind no longer pays those utility graphs during boot. Thanks @vincentkoc.
- Gateway/startup: defer isolated cron runner imports until `/hooks/agent` dispatch so Gateway boot skips the agent-turn runtime on installs that only need normal HTTP bind. Thanks @vincentkoc.
- Gateway/startup: split hook request parsing into a request-path module and load the Gateway hook dispatcher only when a request matches the hooks base path, keeping hook mapping and throttle helpers off plain HTTP bind. Thanks @vincentkoc.
- CLI/Gateway: use a parse-only config snapshot for plain `gateway status` reads and reuse same-path service config context so status no longer spends tens of seconds in full config validation before printing. Thanks @vincentkoc.
- Gateway/startup: defer QMD, core request handlers, setup wizard, CLI outbound senders, plugin HTTP routes, chat/session projection, node session runtime validation, embedded-run activity reads, MCP loopback server imports, channel runtime helpers, HTTP/canvas/plugin auth helpers, isolated cron imports, and hook dispatch parsing until their request or shutdown paths, while making plain `gateway status` use a parse-only config snapshot so no-plugin boots and status reads avoid broad runtime fanout. Thanks @vincentkoc.
- Lobster/Gateway: memoize repeated Ajv schema compilation before loading the embedded Lobster runtime so scheduled workflows and `llm.invoke` loops stop growing gateway heap on content-identical schemas. Fixes #71148. Thanks @cmi525, @vsolaz, and @vincentkoc.
- Codex harness: normalize cached input tokens before session/context accounting so prompt cache reads are not double-counted in `/status`, `session_status`, or persisted `sessionEntry.totalTokens`. Fixes #69298. Thanks @richardmqq.
- Hooks/session-memory: use the host local timezone for memory filenames, fallback timestamp slugs, and markdown headers instead of UTC dates. Fixes #46703. (#46721) Thanks @Astro-Han.
@@ -249,35 +194,12 @@ Docs: https://docs.openclaw.ai
- Logging: write validated diagnostic trace context as top-level `traceId`, `spanId`, `parentSpanId`, and `traceFlags` fields in file-log JSONL records so traced requests and model calls are easier to correlate in log processors. Refs #40353. Thanks @liangruochong44-ui.
- Logging/sessions: apply configured redaction patterns to persisted session transcript text and accept escaped character classes in safe custom redaction regexes, so transcript JSONL no longer keeps matching sensitive text in the clear. Fixes #42982. Thanks @panpan0000.
- Agents/sessions: let `sessions_spawn runtime="subagent"` ignore ACP-only `streamTo` and `resumeSessionId` fields while keeping ACP passthrough and documenting `streamTo` as ACP-only. Fixes #43556 and #63120; covers #56326, #61724, #64714, and #67248; carries forward #68397, #65282, #58686, #56342, and #40102. Thanks @skernelx, @damselem, @Br1an67, @Mintalix, @IsaacAPerez, @vvitovec, @Sanjays2402, @shenkq97, and @1034378361.
- Providers/Ollama: honor `/api/show` capabilities when registering local models so non-tool Ollama models no longer receive the agent tool surface, and keep native Ollama thinking opt-in instead of enabling it by default. Fixes #64710 and duplicate #65343. Thanks @yuan-b, @netherby, @xilopaint, and @Diyforfun2026.
- Providers/Ollama: honor `/api/show` capabilities, custom Modelfile `PARAMETER num_ctx`, configured provider/model context defaults, whitelisted native params such as `temperature`, `top_p`, and `think`, and native thinking effort levels so local models get accurate tools, context, and thinking behavior without forcing full-context VRAM use. Fixes #64710, duplicate #65343, #68344, #44550, #52206, #49684, #68662, #48010, #71584, and #44786; supersedes #69464; carries forward #44955. Thanks @yuan-b, @netherby, @xilopaint, @Diyforfun2026, @neeravmakwana, @taitruong, @armi0024, @LokiCode404, @zhouZcong, @dshenster-byte, @tangzhi, @pandego, @maweibin, @Adam-Researchh, @EmpireCreator, @g0st1n, and @voltwake.
- Image tool/media: honor `tools.media.image.timeoutSeconds` and matching per-model image timeouts in explicit image analysis, including the MiniMax VLM fallback path, so slow local vision models are not capped by hardcoded 30s/60s aborts. Fixes #67889; supersedes #67929. Thanks @AllenT22 and @alchip.
- Providers/Ollama: read larger custom Modelfile `PARAMETER num_ctx` values from `/api/show` so auto-discovered Ollama models with expanded context no longer stay pinned to the base model context. Fixes #68344. Thanks @neeravmakwana.
- Providers/Ollama: honor configured model `params.num_ctx` in native and OpenAI-compatible Ollama requests so local models can cap runtime context without rebuilding Modelfiles. Fixes #44550 and #52206; supersedes #69464. Thanks @taitruong, @armi0024, and @LokiCode404.
- Providers/Ollama: stop forcing native Ollama requests to use the full configured `contextWindow` as `options.num_ctx` unless `params.num_ctx` is explicit, so local models can keep Ollama's VRAM/env default instead of looking hung on first turns. Fixes #49684 and #68662. Thanks @zhouZcong and @dshenster-byte.
- Providers/Ollama: forward whitelisted native Ollama model params such as `temperature`, `top_p`, and top-level `think` so users can disable API-level thinking or tune local models from config without proxy shims. Fixes #48010. Thanks @tangzhi, @pandego, @maweibin, @Adam-Researchh, and @EmpireCreator.
- Providers/Ollama: expose native Ollama thinking effort levels so `/think max` is accepted for reasoning-capable Ollama models and maps to Ollama's highest supported `think` effort. Fixes #71584. Thanks @g0st1n.
- Providers/Ollama: strip the active custom Ollama provider prefix before native chat and embedding requests, so custom provider ids like `ollama-spark/qwen3:32b` reach Ollama as the real model name. Fixes #72353. Thanks @maximus-dss and @hclsys.
- Providers/Ollama: parse stringified native tool-call arguments before dispatch, preserving unsafe integer values so Ollama tool use receives structured parameters. Fixes #69735; supersedes #69910. Thanks @rongshuzhao and @yfge.
- Providers/Ollama: skip ambient localhost discovery unless Ollama auth or meaningful config opts in, preventing unexpected probes to `127.0.0.1:11434` for users who are not using Ollama. Fixes #56939; supersedes #57116. Thanks @IanxDev and @tsukhani.
- Providers/Ollama: skip implicit localhost discovery when a custom remote `api: "ollama"` provider is configured, while still treating `127/8` loopback hosts as local. Carries forward #43224. Thanks @issacthekaylon.
- Providers/models: honor provider-level `contextWindow`, `contextTokens`, and `maxTokens` as defaults when resolving discovered models, so local Ollama and other self-hosted providers can cap all models without repeating per-model entries. Fixes #44786; carries forward #44955. Thanks @voltwake and @maweibin.
- Providers/Ollama: move memory embeddings to Ollama's current `/api/embed` endpoint with batched `input` requests while preserving vector normalization and custom provider auth/header overrides. Fixes #39983. Thanks @sskkcc and @LiudengZhang.
- Providers/Ollama: route local web search through Ollama's signed `/api/experimental/web_search` daemon proxy, use hosted `/api/web_search` directly for `ollama.com`, and keep `OLLAMA_API_KEY` scoped to cloud fallback auth. Fixes #69132. Thanks @yoon1012 and @hyspacex.
- Providers/Ollama: accept OpenAI SDK-style `baseURL` as an alias for `baseUrl` across discovery, streaming, setup pulls, embeddings, and web search so remote Ollama hosts are not silently ignored. Fixes #62533; supersedes #62549. Thanks @Julien-BKK and @Linux2010.
- Providers/Ollama: scope synthetic local auth and embedding bearer headers to declared Ollama host boundaries so cloud keys are not sent to local/self-hosted embedding endpoints and remote/cloud Ollama endpoints no longer receive the `ollama-local` marker as if it were a real token. Supersedes #69261 and #69857; refs #43945. Thanks @hyspacex, @maxramsay, and @Meli73.
- Providers/Ollama: resolve custom-named local Ollama providers such as `ollama-remote` through the Ollama synthetic-auth hook so subagents no longer miss `ollama-local` auth and silently fall back to cloud models. Fixes #43945. Thanks @Meli73 and @maxramsay.
- Providers/Ollama: add provider-scoped model request timeouts, thread them through guarded fetch connect/header/body/abort handling, and document `params.keep_alive` for cold local models so first-turn Ollama loads no longer require global agent timeout changes. Fixes #64541 and #68796; supersedes #65143 and #66511. Thanks @LittleJakub, @Juankcba, @uninhibite-scholar, and @yfge.
- Providers/Ollama: preserve explicit configured model input modalities when merging discovered provider metadata so custom vision models keep image support instead of silently dropping attachments. Fixes #39690; carries forward #39785. Thanks @Skrblik and @Mriris.
- Providers/Ollama: estimate native Ollama transcript usage when `/api/chat` omits prompt/eval counters while preserving exact zero counters, keeping local model runs visible in usage surfaces. Carries forward #39112. Thanks @TylonHH.
- Agents/Ollama: retry native Ollama turns that finish without user-visible text, including unsigned thinking-only responses, so constrained reasoning turns can continue instead of surfacing an empty reply. Carries forward #66552 and #61223. Thanks @yfge and @L3G.
- Docs/Ollama: expand setup recipes for local, LAN, cloud, multi-host, web search, embeddings, thinking control, and large-context troubleshooting.
- Providers/Ollama: strip custom provider prefixes before native chat/embedding requests, skip ambient localhost discovery unless config/auth opts in, handle custom remote `api: "ollama"` providers, accept OpenAI SDK-style `baseURL`, scope synthetic local auth and embedding bearer headers to declared host boundaries, resolve custom-named local providers for subagents, add provider-scoped model request timeouts, preserve explicit input modalities, and document `params.keep_alive` plus local/LAN/cloud/multi-host/web-search/embedding/thinking setup recipes. Fixes #72353, #56939, #62533, #43945, #64541, #68796, and #39690; supersedes #57116, #62549, #69261, #69857, #65143, and #66511; refs #43945; carries forward #43224 and #39785. Thanks @maximus-dss, @hclsys, @IanxDev, @tsukhani, @issacthekaylon, @Julien-BKK, @Linux2010, @hyspacex, @maxramsay, @Meli73, @LittleJakub, @Juankcba, @uninhibite-scholar, @yfge, @Skrblik, and @Mriris.
- Providers/Ollama: move memory embeddings to `/api/embed` with batched `input`, route local web search through Ollama's signed daemon proxy while keeping cloud auth scoped, treat Ollama memory embeddings as key-optional in doctor, and keep model usage visible by estimating native transcript usage when `/api/chat` omits counters. Fixes #39983, #69132, and #46584; carries forward #39112. Thanks @sskkcc, @LiudengZhang, @yoon1012, @hyspacex, @fengly78, and @TylonHH.
- Agents/Ollama: parse stringified native tool-call arguments, retry native empty/thinking-only turns, accept already-prefixed LLM task model overrides, apply provider-owned replay normalization for Cloud models, validate explicit `--thinking max`, show resolved thinking defaults in Control UI, and include configured provider models in `models list --provider`. Fixes #69735, #50052, #71697, #71584, #72407, and #65207; supersedes #69910; carries forward #66552 and #61223. Thanks @rongshuzhao, @yfge, @L3G, @ralphy-maplebots, @Hollychou924, @ismael-81, @g0st1n, @NotecAG, and @drzeast-png.
- Providers/PDF/Ollama: add bounded network timeouts for Ollama model pulls and native Anthropic/Gemini PDF analysis requests so unresponsive provider endpoints no longer hang sessions indefinitely. Fixes #54142; supersedes #54144 and #54145. Thanks @jinduwang1001-max and @arkyu2077.
- LLM Task/Ollama: accept model overrides that already include the selected provider prefix, avoiding doubled ids such as `ollama/ollama/llama3.2:latest`, and live-verify local Ollama JSON tasks return parsed output. Fixes #50052. Thanks @ralphy-maplebots and @Hollychou924.
- Memory/doctor: treat Ollama memory embeddings as key-optional so `openclaw doctor` no longer warns about a missing API key when the gateway reports embeddings are ready. Fixes #46584. Thanks @fengly78.
- Agents/Ollama: apply provider-owned replay turn normalization to native Ollama chat so Cloud models no longer reject non-alternating replay history in agent/Gateway runs. Fixes #71697. Thanks @ismael-81.
- Control UI/Ollama: show the resolved configured thinking default in chat and session thinking dropdowns so inherited `adaptive`/per-model thinking config no longer appears as `Default (off)` or a generic inherit value. Fixes #72407. Thanks @NotecAG.
- Agents/Ollama: validate explicit `--thinking max` against catalog-discovered Ollama reasoning metadata so local agent runs accept the same native thinking levels shown in the model catalog. Fixes #71584. Thanks @g0st1n.
- CLI/models: include explicitly configured provider models in `openclaw models list --provider <id>` without requiring the full catalog path, so configured Ollama models are visible. Fixes #65207. Thanks @drzeast-png.
- Docker/QA: add observability coverage to the normal Docker aggregate so QA-lab OTEL and Prometheus diagnostics run inside Docker. Thanks @vincentkoc.
- Auto-reply: poison inbound message dedupe after replay-unsafe provider/runtime failures so retries stay safe before visible progress but cannot duplicate messages after block output, tool side effects, or session progress. Fixes #69303; keeps #58549 and #64606 as duplicate validation. Thanks @martingarramon, @NikolaFC, and @zeroth-blip.
- Agents/model fallback: keep auto-persisted fallback model overrides selected across turns until `/new` or reset clears them, avoiding repeated probes of a known-bad primary while `/status` shows the selected and active models. Thanks @kibedu.
@@ -285,11 +207,7 @@ Docs: https://docs.openclaw.ai
- Gateway/Bonjour: keep @homebridge/ciao cancellation handlers registered across advertiser restarts so late probing cancellations cannot crash Linux and other mDNS-churned gateways.
- Plugins/startup: load the default `memory-core` slot during Gateway startup when permitted so active-memory recall can call `memory_search` and `memory_get` without requiring an explicit `plugins.slots.memory` entry, while preserving `plugins.slots.memory: "none"`.
- Plugins/CLI: prefer native require for compiled bundled plugin JavaScript before jiti so read-only config, status, device, and node commands avoid unnecessary transform overhead on slow hosts. Fixes #62842. Thanks @Effet.
- Plugins/compat: inventory doctor-side deprecation migrations separately from runtime plugin compatibility so release sweeps preserve needed repairs while enforcing dated removal windows. Thanks @vincentkoc.
- Plugins/compat: add missing dated compatibility records for legacy extension-api, memory registration, provider hook/type aliases, runtime aliases, channel SDK helpers, and approval/test utility shims. Thanks @vincentkoc.
- Plugins/CLI: refresh the persisted registry after managed plugin files are removed so ClawHub uninstall cannot leave stale `plugins list` entries.
- Plugins/CLI: make plugin install and uninstall config writes conflict-aware, clear stale denylist entries on explicit reinstall/removal, and delete managed plugin files only after config/index commit succeeds.
- Plugins: fail `plugins update` when tracked plugin or hook updates error, keep bundled runtime-dependency repair behind restrictive allowlists, and reject package installs with unloadable extension entries.
- Plugins/compat/CLI: inventory doctor-side deprecation migrations separately from runtime plugin compatibility, add dated records for legacy extension-api, memory registration, provider hook/type aliases, runtime aliases, channel SDK helpers, and approval/test utility shims, refresh the persisted registry after managed plugin removals, make plugin install/uninstall writes conflict-aware, clear stale denylists, and fail tracked plugin/hook updates or unloadable package installs instead of leaving stale state. Thanks @vincentkoc.
- WebChat/Control UI: support non-video file attachments in chat uploads while preserving the existing image attachment path and MIME-sniff fallback for generic image uploads. (#70947) Thanks @IAMSamuelRodda.
- Skills/memory: restore Chokidar v5 hot reloads by watching concrete skill and memory roots with filters, including SKILL.md removals and deleted skill folders without broad workspace recursion. Fixes #27404, #33585, and #41606. Thanks @shelvenzhou, @08820048, and @rocke2020.
- Gateway/chat: keep duplicate attachment-backed `chat.send` retries with the same idempotency key on the documented in-flight path so aborts still target the real active run. Fixes #70139. Thanks @Feelw00.
@@ -305,12 +223,8 @@ Docs: https://docs.openclaw.ai
- Docker/update smoke: keep the package-derived update-channel fixture on package-shipped files and make its UI build stub create the asset the updater verifies. Thanks @vincentkoc.
- Gateway/models: repair legacy `models.providers.*.api = "openai"` config values to `openai-completions`, and skip providers with future stale API enum values during startup instead of bricking the gateway. Fixes #72477. (#72542) Thanks @JooyoungChoi14 and @obviyus.
- Gateway/skills: redact `apiKey` and secret-named `env` values from the `skills.update` RPC response to prevent leaking credentials into WebSocket traffic, client logs, or session transcripts. Config is still written to disk in full; only the response payload is redacted. (#69998) Thanks @Ziy1-Tan.
- Plugins/CLI: let flag-driven `openclaw channels add` install the selected channel plugin from its default source without opening an interactive prompt, fixing published npm Telegram setup in stdin-closed automation.
- Onboarding/setup: keep first-run config reads, plugin compatibility notices, and post-model sanity checks on cold metadata paths unless the user chooses to browse all models, avoiding full plugin/runtime catalog work between prompts. Thanks @shakkernerd.
- Onboarding/auth: run manifest-owned provider auth choices through scoped setup providers so selecting OpenAI Codex browser/device auth no longer loads every provider runtime before OAuth starts. Thanks @shakkernerd.
- Onboarding/auth: keep the post-auth default-model policy lookup on manifest/setup metadata so the next prompt appears without loading broad provider runtime. Thanks @shakkernerd.
- Onboarding/models: keep skip-auth and provider-scoped model picker prompts off the full global model catalog path, and cache provider catalog hook resolution so setup no longer stalls after auth on large plugin registries. Thanks @shakkernerd.
- Onboarding/setup: keep first-run config reads, plugin compatibility notices, OpenAI Codex auth, post-auth default-model policy lookup, skip-auth, provider-scoped model pickers, and post-model sanity checks on cold manifest/setup metadata unless the user chooses to browse all models, avoiding full plugin/provider runtime loads between prompts. Thanks @shakkernerd.
- Gateway/Bonjour: suppress known @homebridge/ciao cancellation and network assertion failures through scoped process handlers so malformed mDNS packets or restricted VPS networking disable/restart Bonjour instead of crashing the gateway. Fixes #67578. Thanks @zenassist26-create.
- Discord: keep late clicks on already-resolved exec approval buttons quiet when elevated mode auto-resolved the request, while still surfacing real approval submission failures. Fixes #66906. Thanks @rlerikse.
- Telegram: send a fresh final message for long-lived preview-streamed replies so the visible Telegram timestamp reflects completion time instead of the preview creation time. Thanks @rubencu.

View File

@@ -1,4 +1,4 @@
51586a795b6e1b821b3ccb2ef8e92e69ba4ef65fea254738b5a0b7b380d91bd1 config-baseline.json
f84f0e7ad9e5334779bfc6dbeb849a64fd9feed99bef3ba23104a2f31d9a4a88 config-baseline.json
7dcb21e47ddd5de98e2af1ecbc41e11ac0c5742819c359e6d851fbc39c0226e9 config-baseline.core.json
07963db49502132f26db396c56b36e018b110e6c55a68b3cb012d3ec96f43901 config-baseline.channel.json
13d038300d90d4dd064aa2ac79def867799d1be403cf9d3e81dfad35ef459a21 config-baseline.plugin.json
6f7e255d4520ba18364771faca375c0971bb68472c4a0bd3e55c032407042067 config-baseline.channel.json
6938050627f0d120109d2045b4300aa8b508b35132542db434033ed0fe3e2b3a config-baseline.plugin.json

View File

@@ -1,2 +1,2 @@
7178659d932136074130426d08e596738a991c6812b2494149427d1f822f1be8 plugin-sdk-api-baseline.json
fc1e3ab9f21b6f7b6a55498cf5ee322d62dccf4c23322f0ba27559e55a59f901 plugin-sdk-api-baseline.jsonl
9a9970607c4ee25d8b493ea1bb1ecef939dc11330c16188251bd69eee7ab6b2d plugin-sdk-api-baseline.json
e37f1ec7f6a9b19466ab09935f713890f375cc6c8d67647dca701140a989f5f4 plugin-sdk-api-baseline.jsonl

View File

@@ -14,7 +14,9 @@ manual `CI` workflow with that target, and dispatches `OpenClaw Release Checks`
for install smoke, package acceptance, Docker release-path suites, live/E2E,
OpenWebUI, QA Lab parity, Matrix, and Telegram lanes. It can also run the
post-publish `NPM Telegram Beta E2E` workflow when a published package spec is
provided. The umbrella records the dispatched child run ids, and the final
provided. For unpublished package candidates, `OpenClaw Release Checks` runs
Package Acceptance with `source=ref` and Telegram package QA against the packed
tarball. The umbrella records the dispatched child run ids, and the final
`Verify full validation` job re-checks the current child run conclusions. If a
child workflow is rerun and turns green, rerun only the parent verifier job to
refresh the umbrella result.
@@ -37,7 +39,9 @@ Docker lane selections. The `package` profile uses offline plugin coverage so
published-package validation is not gated on live ClawHub availability. The
optional Telegram lane reuses the
`package-under-test` artifact in the `NPM Telegram Beta E2E` workflow, with the
published npm spec path kept for standalone dispatches.
published npm spec path kept for standalone dispatches. Standalone Telegram
dispatch can also pack a trusted branch/tag/SHA, verify an HTTPS tarball URL
plus SHA-256, or reuse a tarball artifact from another run.
## Package acceptance
@@ -165,6 +169,26 @@ gh workflow run package-acceptance.yml \
-f docker_lanes='install-e2e plugin-update'
```
Use standalone `NPM Telegram Beta E2E` when only the Telegram package lane is
needed:
```bash
# Exact published npm proof.
gh workflow run npm-telegram-beta-e2e.yml \
--ref main \
-f source=npm \
-f package_spec=openclaw@YYYY.M.D-beta.N \
-f provider_mode=mock-openai
# Pre-publish proof from a branch, tag, or full SHA.
gh workflow run npm-telegram-beta-e2e.yml \
--ref main \
-f source=ref \
-f package_ref=release/YYYY.M.D \
-f harness_ref=main \
-f provider_mode=mock-openai
```
When debugging a failed package acceptance run, start at the `resolve_package`
summary to confirm the package source, version, and SHA-256. Then inspect the
`docker_acceptance` child run and its Docker artifacts:

View File

@@ -168,8 +168,10 @@ the fast Matrix and Telegram lanes before release approval.
- `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci|maintainer` overrides the shared
`OPENCLAW_QA_CREDENTIAL_ROLE` for this lane only.
- GitHub Actions exposes this lane as the manual maintainer workflow
`NPM Telegram Beta E2E`. It does not run on merge. The workflow uses the
`qa-live-shared` environment and Convex CI credential leases.
`NPM Telegram Beta E2E`. It does not run on merge. The workflow can install
a published npm spec, pack a trusted branch/tag/SHA, verify an HTTPS tarball
URL plus SHA-256, or reuse a tarball artifact from another Actions run. It
uses the `qa-live-shared` environment and Convex CI credential leases.
- GitHub Actions also exposes `Package Acceptance` for side-run product proof
against one candidate package. It accepts a trusted ref, published npm spec,
HTTPS tarball URL plus SHA-256, or tarball artifact from another run, uploads

View File

@@ -103,7 +103,10 @@ the maintainer-only release runbook.
`OpenClaw Release Checks` for install smoke, package acceptance, Docker
release-path suites, live/E2E, OpenWebUI, QA Lab parity, Matrix, and Telegram
lanes. Provide `npm_telegram_package_spec` only after a package has been
published and the post-publish Telegram E2E should run too. Example:
published and the post-publish Telegram E2E should run too. Provide
`evidence_package_spec` when the private evidence report should prove that the
validation matches a published npm package without forcing Telegram E2E.
Example:
`gh workflow run full-release-validation.yml --ref main -f ref=release/YYYY.M.D`
- Run the manual `Package Acceptance` workflow when you want side-channel proof
for a package candidate while release work continues. Use `source=npm` for
@@ -180,7 +183,10 @@ Validation` or from the `main`/release workflow ref so workflow logic and
`OPENCLAW_QA_TELEGRAM_*` env credentials directly.
- Maintainers can run the same post-publish check from GitHub Actions via the
manual `NPM Telegram Beta E2E` workflow. It is intentionally manual-only and
does not run on every merge.
does not run on every merge. For pre-publish Telegram-only proof, run the
same workflow with `source=ref` and `package_ref=<branch-or-sha>` so CI packs
the candidate tarball before exercising Telegram. For exact registry proof
after publish, keep `source=npm` and `package_spec=openclaw@<version>`.
- Maintainer release automation now uses preflight-then-promote:
- real npm publish must pass a successful npm `preflight_run_id`
- the real npm publish must be dispatched from the same `main` or
@@ -233,7 +239,8 @@ gh workflow run full-release-validation.yml \
--ref main \
-f ref=release/YYYY.M.D \
-f provider=openai \
-f mode=both
-f mode=both \
-f evidence_package_spec=openclaw@YYYY.M.D-beta.N
```
The workflow resolves the target ref, dispatches manual `CI` with
@@ -244,7 +251,10 @@ install smoke, cross-OS release checks, live/E2E Docker release-path coverage,
Package Acceptance with Telegram package QA, QA Lab parity, live Matrix, and
live Telegram. A full run is only acceptable when the `Full Release Validation`
summary shows `normal_ci` and `release_checks` as successful, and any optional
`npm_telegram` child is either successful or intentionally skipped.
`npm_telegram` child is either successful or intentionally skipped. A skipped
`npm_telegram` child only means no exact published npm package was supplied;
the pre-publish tarball-backed Telegram package proof still runs inside
`OpenClaw Release Checks` through Package Acceptance.
Child workflows are dispatched from the trusted ref that runs `Full Release
Validation`, normally `--ref main`, even when the target `ref` points at an
older release branch or tag. There is no separate Full Release Validation
@@ -273,10 +283,32 @@ gh workflow run full-release-validation.yml \
-f ref=release/YYYY.M.D \
-f provider=openai \
-f mode=both \
-f evidence_package_spec=openclaw@YYYY.M.D-beta.N \
-f npm_telegram_package_spec=openclaw@YYYY.M.D-beta.N \
-f npm_telegram_provider_mode=mock-openai
```
For focused Telegram package proof before publishing, use the standalone
`NPM Telegram Beta E2E` workflow with the same package candidate shapes as
Package Acceptance:
```bash
# Pack and test a release branch or exact SHA through Telegram.
gh workflow run npm-telegram-beta-e2e.yml \
--ref main \
-f source=ref \
-f package_ref=release/YYYY.M.D \
-f harness_ref=main \
-f provider_mode=mock-openai
# Exact published package proof after beta/stable publish.
gh workflow run npm-telegram-beta-e2e.yml \
--ref main \
-f source=npm \
-f package_spec=openclaw@YYYY.M.D-beta.N \
-f provider_mode=mock-openai
```
Do not use the full umbrella as the first rerun after a focused fix. If one box
fails, use the failed child workflow, job, Docker lane, package profile, model
provider, or QA lane for the next proof. Run the full umbrella again only when

View File

@@ -233,6 +233,13 @@ function resolveLiveVideoSkipReason(message: string): string | null {
if (isOverloadedErrorMessage(message) || isServerErrorMessage(message)) {
return "provider outage";
}
if (
/HTTP\s+404/i.test(message) &&
/Invalid URL/i.test(message) &&
/\/platform\/video_gen/i.test(message)
) {
return "provider endpoint drift";
}
if (/access denied|not authorized|not enabled|permission denied/i.test(message)) {
return "provider/model drift";
}

View File

@@ -185,7 +185,7 @@ describeLive("xai plugin live", () => {
const realtimeProvider = requireRegisteredProvider(realtimeTranscriptionProviders, "xai");
const speechProvider = requireRegisteredProvider(speechProviders, "xai");
const cfg = createLiveConfig();
const phrase = "OpenClaw xAI realtime transcription integration test OK.";
const phrase = "Speech transcription check okay.";
const telephony = await speechProvider.synthesizeTelephony?.({
text: phrase,
@@ -216,6 +216,7 @@ describeLive("xai plugin live", () => {
language: "en",
},
audio: telephony.audioBuffer,
expectedNormalizedText: "speechtranscription",
chunkSize,
delayMs: 20,
closeBeforeWait: true,
@@ -223,7 +224,7 @@ describeLive("xai plugin live", () => {
const normalized = transcripts.join(" ").toLowerCase();
const compact = normalizeTranscriptForMatch(normalized);
expect(compact).toContain("openclaw");
expect(compact).toContain("speechtranscription");
expect(normalized).toContain("transcription");
expect(partials.length + transcripts.length).toBeGreaterThan(0);
}, 180_000);

View File

@@ -764,7 +764,8 @@ function Invoke-OpenClawUpdateWithTimeout {
}
Remove-Job $updateJob -Force -ErrorAction SilentlyContinue
if ($result.ExitCode -ne 0) {
throw "openclaw update failed with exit code $($result.ExitCode)"
Write-ProgressLog 'update.openclaw-update.nonzero'
"openclaw update exited with code $($result.ExitCode); continuing to installed-version and gateway recovery checks" | Tee-Object -FilePath $LogPath -Append | Out-Null
}
return
}

View File

@@ -219,6 +219,14 @@ describe("isProviderUnavailableErrorMessage", () => {
isProviderUnavailableErrorMessage("provider returned error: 502 Internal Server Error"),
).toBe(true);
});
it("matches transient xAI model unavailability", () => {
expect(
isProviderUnavailableErrorMessage(
"Error Code null: Service temporarily unavailable. The model did not respond to this request.",
),
).toBe(true);
});
});
function isChatGPTUsageLimitErrorMessage(raw: string): boolean {
@@ -257,8 +265,10 @@ function isProviderUnavailableErrorMessage(raw: string): boolean {
isCloudflareOrHtmlErrorPage(raw) ||
msg.includes("no allowed providers are available") ||
msg.includes("provider unavailable") ||
msg.includes("service temporarily unavailable") ||
msg.includes("upstream provider unavailable") ||
msg.includes("upstream error from google") ||
msg.includes("the model did not respond") ||
msg.includes("temporarily rate-limited upstream") ||
msg.includes("unable to access non-serverless model") ||
msg.includes("create and start a new dedicated endpoint") ||

View File

@@ -313,14 +313,19 @@ exit 0
expect(scriptPath.endsWith(".cmd")).toBe(true);
expect(content).toContain("@echo off");
expect(content).toContain("powershell -NoProfile -ExecutionPolicy Bypass -Command");
expect(content).not.toContain("-File");
expect(content).not.toContain("powershell -NoProfile -ExecutionPolicy Bypass -File");
expect(content).toContain('$ErrorActionPreference = "Continue"');
expect(content).toContain("gateway-restart.log");
expect(content).toContain("$taskName = 'OpenClaw Gateway'");
expect(content).toContain("function Invoke-OpenClawSchtasksWithTimeout");
expect(content).toContain("function Get-OpenClawScheduledTaskState");
expect(content).toContain("function Invoke-OpenClawStartupLauncher");
expect(content).toContain("Get-ScheduledTask -TaskName $TaskName");
expect(content).toContain("openclaw restart skipped schtasks end");
expect(content).toContain(
'$launcherPath = Join-Path $env:USERPROFILE ".openclaw\\gateway.cmd"',
);
expect(content).toContain("openclaw restart launched startup fallback");
expectWindowsRestartWaitOrdering(content);
expect(content).toContain('del "%~f0" >nul 2>&1');
await cleanupScript(scriptPath);
@@ -338,6 +343,7 @@ exit 0
expect(content).toContain(
'Invoke-OpenClawSchtasksWithTimeout -Arguments @("/End", "/TN", $taskName) -TimeoutSeconds 10',
);
expect(content).toContain("$status = Invoke-OpenClawStartupLauncher");
expectWindowsRestartWaitOrdering(content);
await cleanupScript(scriptPath);
});

View File

@@ -281,6 +281,23 @@ function Get-OpenClawListenerPids {
$listenerPids | Sort-Object -Unique
}
function Invoke-OpenClawStartupLauncher {
$launcherPath = Join-Path $env:USERPROFILE ".openclaw\\gateway.cmd"
if (-not (Test-Path -LiteralPath $launcherPath)) {
Write-RestartLog "openclaw restart startup launcher missing source=update path=$launcherPath"
return 1
}
try {
Start-Process -FilePath $launcherPath -WindowStyle Hidden | Out-Null
Write-RestartLog "openclaw restart launched startup fallback source=update path=$launcherPath"
return 0
} catch {
Write-RestartLog "openclaw restart startup fallback failed source=update error=$($_.Exception.Message)"
return 1
}
}
$taskName = ${quotedTaskName}
$port = ${port}
Write-RestartLog "openclaw restart attempt source=update target=$taskName"
@@ -317,6 +334,9 @@ for ($attempt = 1; $attempt -le 10; $attempt++) {
}
$status = Invoke-OpenClawSchtasksWithTimeout -Arguments @("/Run", "/TN", $taskName) -TimeoutSeconds 30
if ($status -ne 0) {
$status = Invoke-OpenClawStartupLauncher
}
if ($status -eq 0) {
Write-RestartLog "openclaw restart done source=update"
} else {

View File

@@ -10010,6 +10010,9 @@ export const GENERATED_BUNDLED_CHANNEL_CONFIG_METADATA = [
type: "string",
enum: ["off", "partial"],
},
c2cStreamApi: {
type: "boolean",
},
},
required: ["mode"],
additionalProperties: {},
@@ -10250,6 +10253,9 @@ export const GENERATED_BUNDLED_CHANNEL_CONFIG_METADATA = [
type: "string",
enum: ["off", "partial"],
},
c2cStreamApi: {
type: "boolean",
},
},
required: ["mode"],
additionalProperties: {},

View File

@@ -251,6 +251,18 @@ describe("gateway codex harness live helpers", () => {
expect(isExpectedCodexModelsCommandText(text)).toBe(true);
});
it("accepts the interactive TUI header summary from Docker live harness", () => {
const text = [
"`codex models` is interactive here and did not print a model list. It opened a Codex TUI session, which interpreted `models` as a prompt and replied:",
"",
"> Could you clarify what you want to do with “models”?",
"",
"The visible session header showed the current model as `gpt-5.5`.",
].join("\n");
expect(isExpectedCodexModelsCommandText(text)).toBe(true);
});
it("accepts the local Codex model-cache summary", () => {
const text = [
"Available models in this Codex install, from the local cache fetched on `2026-04-18`, are:",

View File

@@ -211,6 +211,11 @@ export function isExpectedCodexModelsCommandText(text: string): boolean {
mentionsInteractiveSelection &&
normalized.includes("plain list") &&
mentionsCurrentSelectedModel;
const isInteractiveTuiHeaderSummary =
mentionsCodexModelsCommand &&
(normalized.includes("interactive here") || normalized.includes("interactive tui")) &&
(normalized.includes("did not print a model list") || normalized.includes("plain list")) &&
normalized.includes("visible session header showed the current model");
return (
isSandboxFallback ||
@@ -218,6 +223,7 @@ export function isExpectedCodexModelsCommandText(text: string): boolean {
isInteractiveSelectionSummary ||
isAgentIdModelSummary ||
isAvailableHereModelSummary ||
isInteractiveTuiSummary
isInteractiveTuiSummary ||
isInteractiveTuiHeaderSummary
);
}