Summary:
- The PR feeds loopback-scoped MCP tools into CLI system prompts and reports, persists a prompt tool-name hash for CLI session reuse, adds regression tests, and adds a changelog entry.
- Reproducibility: yes. from source inspection: current main builds the CLI prompt and report with `tools: []` ... execute a live CLI turn in this read-only review, but the source path and source PR terminal proof line up.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(cli): gate prompt loopback tools on active runtime
- PR branch already contained follow-up commit before automerge: fix(cli): include loopback tools in cli prompts
Validation:
- ClawSweeper review passed for head d196564d4d.
- Required merge gates passed before the squash merge.
Prepared head SHA: d196564d4d
Review: https://github.com/openclaw/openclaw/pull/83828#issuecomment-4483469332
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The replacement PR adds a `watch-targets` skills snapshot invalidation when `ensureSkillsWatcher` rebuilds f ... root set, reads the snapshot version after watcher setup, adds regression tests, and updates the changelog.
- Reproducibility: yes. Source inspection shows current main rebuilds the skills watcher on changed root targe ... the version before watcher setup; I did not run a live Gateway mount reproduction in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(skills): refresh snapshots when watch roots change
Validation:
- ClawSweeper review passed for head 2677dcc35a.
- Required merge gates passed before the squash merge.
Prepared head SHA: 2677dcc35a
Review: https://github.com/openclaw/openclaw/pull/83823#issuecomment-4483425019
Co-authored-by: hclsys <hclsys@openclaw.ai>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR adds Anthropic Claude 4.x image-capability normalization for stale text-only resolved model rows, regression tests for provider and fallback model resolution, and a changelog entry.
- Reproducibility: yes. for source-level reproduction: current main gates native images on model.input includi ... s text-only. I did not run the command locally because this review was constrained to read-only inspection.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(anthropic): preserve Claude image capability
Validation:
- ClawSweeper review passed for head 06dd378ea3.
- Required merge gates passed before the squash merge.
Prepared head SHA: 06dd378ea3
Review: https://github.com/openclaw/openclaw/pull/83756#issuecomment-4482116499
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR passes the effective OpenAI/Codex auth provider set into `/models` provider-header labeling, adds focused regression tests, and records the user-facing fix in the changelog.
- Reproducibility: yes. Current main lacks `acceptedProviderIds` in the shared picker header path, and the source PR's Mantis baseline/candidate proof shows the visible Telegram header mismatch and after-fix OAuth label.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(models): label picker auth via effective provider order
Validation:
- ClawSweeper review passed for head 8ca2924adc.
- Required merge gates passed before the squash merge.
Prepared head SHA: 8ca2924adc
Review: https://github.com/openclaw/openclaw/pull/83726#issuecomment-4480805713
Co-authored-by: Stellar鱼 <2182712990@qq.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The branch updates the transcript tail assistant reader to skip trailing non-message rows, adds cache-ttl gap-fill regression tests, and adds a changelog entry.
- Reproducibility: yes. Source inspection shows cache-ttl custom rows can sit after the canonical assistant me ... r stops on that row; the PR body also supplies a concrete live three-turn CLI reproduction after the patch.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(transcript): skip trailing custom entries in tail assistant reade…
Validation:
- ClawSweeper review passed for head 866aa27ca8.
- Required merge gates passed before the squash merge.
Prepared head SHA: 866aa27ca8
Review: https://github.com/openclaw/openclaw/pull/83635#issuecomment-4478637780
Co-authored-by: yaoyi1222 <yaoyi_1222@163.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Follow-up and main reply paths re-entered each embedded fallback candidate
with the same queued transcript prompt. After the first candidate persisted
that queued user message, later candidates appended it again. Failed
embedded candidates could also persist an assistant error stub on each
retry, leaving same-role transcript runs that downstream providers reject.
The fallback callers now keep two persistence latches for one fallback run:
queuedUserMessagePersistedAcrossFallback flips from onUserMessagePersisted,
and assistantErrorPersistedAcrossFallback flips only after the session guard
actually persists an assistant stopReason="error" message. Later candidates
suppress only the entries that were already written, so CLI or otherwise
non-persisting failures do not hide the first embedded error separator.
Plumb the assistant-error persistence callback through the embedded runner,
attempt params, and session guard wrapper. Add guard and runner regression
tests for all-embedded fallback retries and CLI-to-embedded fallback.
Closes#83404
Fixes#83388.
- Honor per-agent `tools.codeMode` in config schema, runtime code-mode resolution, and model payload filtering.
- Preserve grouped OpenAI tool declarations when code-mode filtering keeps only `exec` and `wait`.
- Sync generated config/prompt baselines and carry a narrow media CI unblocker from current `main` fallout.
Co-authored-by: Kaspre <kaspre@gmail.com>
OAuth login flow
----------------
- Hard-require refresh_token after the authorization-code exchange in
xai-oauth.ts. Access-only responses persisted credentials that the
downstream usability check later rejected; the new requireRefreshToken
option fails the exchange instead. Error wording explains the missing
refresh_token in OIDC scope terms (offline_access scope rejected),
not a "grant".
- Derive token expiry from the access-token JWT exp claim when
expires_in is missing. id_token exp is intentionally not used as a
fallback because id_token lifetime tracks the OIDC session, not the
access token, and would defer refresh past actual expiry.
- Handle CORS preflight OPTIONS on the loopback OAuth callback in
src/plugin-sdk/provider-auth-runtime.ts. The previous handler treated
any non-callback request as a failed GET, returned "Missing code or
state", and tore the server down before the real GET arrived. The
CORS allowlist is now an optional `corsOriginAllowlist` parameter on
waitForLocalOAuthCallback so the SDK helper stays generic. The xAI
plugin passes ["auth.x.ai", "accounts.x.ai"] from loginXaiOAuth.
Sidecar surfaces
----------------
- speech-provider.ts (POST /v1/tts) honors the xAI OAuth profile in
addition to provider config and XAI_API_KEY. isConfigured now also
reports true when an xAI auth profile is configured (via
isProviderAuthProfileConfigured), so OAuth-only users are no longer
silently filtered out by the selection layer. The bearer resolver
threads req.cfg into resolveApiKeyForProvider so the right xAI auth
profile is picked when a user has multiple.
- realtime-transcription-provider.ts (WSS /stt) gets the same
isConfigured fix, and the lazy headers() resolver threads req.cfg
into the OAuth bearer lookup. createSession stays sync per its
plugin contract.
- stt.ts: drop the plugin-side OAuth fallback. The media-understanding
core already resolves auth (cfg/agentDir-aware) via
resolveProviderExecutionContext before calling transcribeAudio, so
the wrapper was redundant. transcribeAudio is now the registered
hook directly.
User-Agent attribution
----------------------
- New buildXaiAttributionPolicy in src/agents/provider-attribution.ts
injects User-Agent: openclaw/<version>, originator, and version on
/v1/responses and /v1/chat/completions traffic that goes through
resolveProviderRequestHeaders. Gated to xai-native and default
endpoint classes; custom proxy baseUrls remain withheld. reviewNote
is honest about which headers are spec-verified vs mirrored.
- Shared extensions/xai/src/xai-user-agent.ts helper exports
xaiUserAgentHeaderFor(baseUrl) which only emits the User-Agent when
the resolved baseUrl points at the xAI-native API host. Threaded
through TTS and realtime STT (WS upgrade headers) so user-configured
proxy baseUrls do not receive the openclaw identity. OAuth discovery
and token endpoints still send User-Agent unconditionally because
isTrustedXaiOAuthEndpoint already restricts those URLs to *.x.ai.
- Image gen, batch STT, and video gen rely on the attribution policy
alone (no manual User-Agent in defaultHeaders), so attribution
withholding on user-configured proxy baseUrls is preserved
end-to-end.
- UA is bearer-agnostic: same value whether the bearer comes from an
xAI API key or the xAI OAuth flow.
Drop dead api.grok.x.ai alias
-----------------------------
- xAI retired the api.grok.x.ai alias; DNS now returns NXDOMAIN from
xAI's own authoritative nameservers. Drop it from the xai-native
endpoint host set in extensions/xai/openclaw.plugin.json,
extensions/xai/api.ts, extensions/xai/tts.ts, and the
openai-responses payload policy. Update the attribution test to
classify api.grok.x.ai as "custom" (no live user can reach it; the
classification keeps documenting the host's status).
Video generation now matches xAI's actual API behavior
------------------------------------------------------
Previously, real video generation requests failed with
"xAI video generation response malformed" because the poll-status
handler validated against a closed enum that did not match what the
xAI service actually returns. Four fixes:
- Loosen the poll-status handler. xAI returns intermediate strings
outside `["queued", "processing", "done", "failed", "expired"]`
(commonly `submitted`, `pending`, `in_progress`, ...). Treat `done`
as terminal-success, `["failed", "error", "expired", "cancelled"]`
as terminal-failure, and any other string (including empty) as
continue-polling. Also accept `cancelled` as a terminal failure.
- Send default duration/aspect_ratio/resolution on every generate and
reference-image submit. xAI rejects bodies that omit these fields.
Defaults: duration=8s, aspect_ratio="16:9", resolution="720p".
- Accept lowercase resolution input ("480p"/"720p"/"1080p") in
addition to uppercase, normalize to lowercase on the wire.
- Add an `x-idempotency-key` header (fresh `crypto.randomUUID()`) on
every submit so a network retry does not double-charge the user.
Polls intentionally reuse the unmodified `headers` without the key.
Ergonomics
----------
- All "missing xAI credentials" errors (code_execution, lazy
code_execution fallback in extensions/xai/index.ts, x_search,
web_search grok in web-search-provider.runtime.ts, TTS, batch STT,
realtime STT) now mention `openclaw onboard --auth-choice xai-oauth`
first.
- Dedupe the Grok model-id alias table: model-compat.ts re-exports
normalizeXaiModelId from model-id.ts as normalizeNativeXaiModelId.
Test coverage
-------------
- src/plugin-sdk/provider-auth-runtime.test.ts: locks the new pure
buildOAuthCallbackOriginResolver gate (allowlist match,
case-normalization, https-only, non-allowlisted hosts dropped,
multi-Origin handling).
- extensions/xai/xai-oauth.test.ts: locks
XAI_OAUTH_CALLBACK_CORS_ORIGIN_ALLOWLIST so loginXaiOAuth keeps
threading the right hosts to the SDK helper.
- extensions/xai/speech-provider.test.ts: OAuth-only auth profile
flips isConfigured to true; cfg threads into the OAuth fallback
resolver.
- extensions/xai/realtime-transcription-provider.test.ts: same +
upgrade headers carry the OAuth bearer end-to-end.
- extensions/xai/stt.test.ts: explicit assertion that transcribeAudio
trusts the core-resolved apiKey (no plugin-side wrapper).
Verification
------------
- pnpm install: clean
- 154/154 vitest tests pass across 13 touched test files
- pnpm check:changed: typecheck core/ext + tests, oxlint core/ext,
runtime guards, dependency pin guard, package patch guard, runtime
import cycles, sidecar loader guard - all green
- pnpm build: 0 errors, 0 [INEFFECTIVE_DYNAMIC_IMPORT] warnings