* Mark active main sessions during restart shutdown
* Type restart marker mock in close tests
* fix(gateway): preserve active run ownership across restart
* fix(gateway): preserve active runs across restart
* fix(gateway): close restart recovery edge cases
* fix(cron): preserve lifecycle ownership across restart
* fix(gateway): release rejected run contexts
* fix(gateway): preserve restart lifecycle ownership
* fix(cron): retain overlapping run ownership
* fix(agents): preserve restart terminal precedence
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Bounds default model browsing to configured/read-only discovery while preserving explicit full-catalog browsing. Reuses prepared plugin metadata and auth state without triggering external CLI discovery on the picker hot path, while retaining provider normalization and canonical runtime aliases.
Verified with focused model tests, official OpenAI and Anthropic transport suites, fresh live tool calls for both providers, a full build, AWS check:changed, remote Docker OpenAI tools E2E, and green PR CI.
Fixes#91809.
Co-authored-by: samson1357924 <98934496+samson1357924@users.noreply.github.com>
context.used_tokens / pct_used were derived from the snapshot's aggregate
prompt total (cacheRead+cacheWrite+input). Over a multi-call tool-loop turn
that is the run AGGREGATE, overstating window occupancy (often past 100%) so a
footer's context gauge pins full while /status shows the true ~7%.
Add two optional fields to PluginHookReplyUsageState and populate them in the
reply path:
- contextUsedTokens: the final call's prompt size (agentMeta.promptTokens) =
real end-of-turn occupancy, a point-in-time state, not the aggregate.
- lastUsage: the final model call's usage only (vs `usage`, the turn
aggregate), so a footer can render the last exchange's i/o + cache.
Both optional and additive; consumers fall back to the aggregate when absent
(correct for single-call turns). Renderer consumption lands separately (#89835).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Addresses review feedback on #89629.
1) Provider-limit resolution no longer defaults to OAuth. getProviderUsageLimits
and getProviderUsageLimitsCached resolved with `credentialType ?? "oauth"`, and
the agent-runner snapshot call passed no credential type, so an api-key OpenAI
turn could borrow cached OAuth/ChatGPT usage windows. Drop the "oauth" default
(missing credential type => no OpenAI usage provider) and thread the turn's
authMode through at the call site. Adds provider-usage.limits.test.ts covering
api-key/no-credential (no fetch), oauth/token (resolves), and non-OpenAI.
2) usageState is documented as best-effort, present only on live dispatcher
delivery. Routed durable and recovered queue replays re-run this hook as a
stateless transform over the original payload (see QueuedDeliveryPayload); a
point-in-time usage snapshot is not stateless and would replay stale after a
restart, so it is intentionally omitted there. Consumers must treat the field
as optional.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Attach a per-turn execution snapshot to the reply_payload_sending hook as
`usageState`, so a plugin (or the future in-core /usage renderer) can render a
per-response usage readout as a pure consumer of the contract — no side calls.
Recorded in agent-runner, consumed in dispatch. Fields: provider, model,
resolvedRef/requested, reasoningEffort, fastMode, fallbackUsed, is_override
(overrideSource), authMode, compactionCount, contextTokenBudget, token usage,
turn cost (USD), duration, owning agentId/sessionId, chatType, the agent
identity (name/emoji), and the active provider's subscription `limits` windows.
reply_payload_sending is the one reply hook universal across every surface
(incl. the Codex app-server, which emits no llm_output/agent_end), so it is the
correct harness-agnostic place for per-turn usage. Limits are resolved by a
core-internal non-blocking SWR helper (src/infra/provider-usage.limits.ts) and
attached to the snapshot — no new plugin-SDK accessor. All fields optional/additive.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Preserve the first native Kimi tool-call ID while rewriting repeated replay occurrences to deterministic OpenAI-style IDs and keeping paired tool results aligned. Moonshot responses-family behavior and providers that do not opt in remain unchanged.
Closes#51593
Co-authored-by: Pluviobyte <Pluviobyte@users.noreply.github.com>
* feat(moonshot): add Kimi K2.7 Code support
* test(moonshot): surface K2.7 live provider errors
* ci(live): accept Kimi key for Moonshot sweeps
* test(moonshot): verify K2.7 across API regions
* fix(cron): report SQLite storage path in cron.status instead of legacy jobs.json
The `cron.status` gateway response returned `storePath` pointing to the
legacy `jobs.json` path, but cron jobs are actually stored in the shared
SQLite state database. This misled operators and agents into looking for
a JSON file that no longer exists.
- Add `storage: "sqlite"` and `sqlitePath` fields to CronStatusSummary
- Mark legacy `storePath` as @deprecated (kept for backward compat)
- Update CLI warning to prefer sqlitePath over storePath
- Add regression assertions in read-ops test
Fixes#91766
* fix(macos): prefer sqlitePath in cron status display
* fix(macos): add sqlitePath to CronSchedulerStatus type
Since 5734193fdf ("fix(plugins): keep metadata snapshot memo fresh",
first shipped in v2026.5.18), the in-process plugin metadata snapshot
memo stores derived-registry results under a key recomputed from the
freshly built snapshot.index, while lookups key off the persisted-index
registry state. On installs where the registry resolves as "derived"
(persisted index absent or not covering the running checkout), the two
keys never match. Worse, the lookup-side adoption loop returns the most
recently stored registryState for the context, so two alternating call
shapes (e.g. the model-catalog build mixing workspace-scoped and global
lookups) each adopt the other shape's state, compute a key that was
never stored, and re-run the full plugin manifest scan - on every call,
forever. Chat /models (and each subsequent provider/model pick) pays
multiple full manifest scans plus all downstream snapshot-identity cache
invalidation per step, pinning a CPU core for seconds on every
interaction, in every chat channel.
Fix: store the memo under the exact memoKey/registryState the call
looked up by, instead of re-deriving a second key from snapshot.index.
Freshness is unchanged - the lookup context hash and the plugin metadata
lifecycle clears (install/reload/doctor) still own invalidation. The
now-unused index parameter of resolvePersistedRegistryMemoState is
removed.
Measured on the author's VPS (real plugin discovery, identical catalog
output of 263 entries on both sides): the full-discovery model catalog
build behind chat /models dropped from ~6.3s to ~0.3s (~21x), with
repeat snapshot lookups going from full rescans to memo hits.
Regression test: alternating derived call shapes must not re-scan
(red on main: 4 scans; green with this fix: 2).
* fix(thinking): apply Claude profile to anthropic-messages catalog rows
When a custom provider (e.g. `jdcloud-anthropic`) fronted Claude Opus over
the native anthropic-messages adapter, `--thinking xhigh` was silently
clamped to `off`. The thinking-profile dispatcher resolves bundled plugin
policy surfaces by exact provider id, so a renamed Anthropic-compatible
provider never reached the anthropic plugin's policy and `xhigh` was not
in the resulting profile.
`auto-reply/thinking.ts` already had a fallback keyed on
`context.api === "anthropic-messages"` that attached
`CLAUDE_FABLE_5_THINKING_PROFILE` for Fable models. Generalize it to use
`resolveClaudeThinkingProfile(modelId, params)` instead — the same
canonical helper the anthropic plugin uses — which still returns the Fable
profile for Fable models and now returns the correct Opus 4.7/4.8 profile
(with `xhigh`/`adaptive`/`max`) for Claude Opus regardless of provider id.
Non-Claude models on anthropic-messages routes still get the base
profile, and a Claude id on a non-Anthropic transport (e.g. an
openai-completions catalog row) is unaffected.
Fixes#91975
* fix(thinking): match native Anthropic includeNativeMax in fallback
Address ClawSweeper P2 review on #92053. The anthropic-messages fallback
in `resolveThinkingProfile` calls `resolveClaudeThinkingProfile` but
omits the `{ includeNativeMax: true }` option that the bundled anthropic
plugin uses (extensions/anthropic/provider-policy-api.ts:38,45).
For native-xhigh Claude families (Opus 4.7/4.8) this had no effect since
the native-xhigh branch already exposes `max`. But adaptive Claude
families that take the adaptive-default branch (e.g. claude-sonnet-4-6,
claude-opus-4-6) silently lost `max` parity on custom anthropic-messages
providers compared to native Anthropic policy.
Also add a regression test on `claude-sonnet-4-6` that verifies the
adaptive-branch path keeps `max` for custom providers.
* docs(thinking): document deliberate compat.xhigh bypass on anthropic-messages
Self-review surfaced a subtle behavior change worth documenting: when the
anthropic-messages fallback was generalized, non-Claude models on this
transport stop honoring catalog `compat.supportedReasoningEfforts: ["xhigh"]`
because they take the Claude base profile instead of falling through to the
later `catalogSupportsXHigh` upgrade path.
This is intentional — anthropic-messages does not carry a generic xhigh
contract; xhigh on this protocol is a Claude-family capability. Add an
inline comment at the resolver site and a regression test that locks the
suppression so the next reader (or a future patch) doesn't accidentally
restore the upgrade path.
* fix(thinking): extract Claude profile to leaf to break import cycle
The previous commits added a `resolveClaudeThinkingProfile` import from
`auto-reply/thinking.ts` to `plugin-sdk/provider-model-shared.ts`. The
shared barrel re-exports `provider-replay-helpers` and `plugins/types`,
which transitively reach back into `auto-reply` via the gateway server
methods chain — creating the madge cycle reported by
`check:madge-import-cycles`:
auto-reply/thinking.ts
-> ... -> plugin-sdk/provider-model-shared.ts
-> plugins/{config-schema, host-hooks, ...} -> plugins/types.ts
Move `BASE_CLAUDE_THINKING_LEVELS`, `isClaudeAdaptiveThinkingDefaultModelId`,
and `resolveClaudeThinkingProfile` to a new leaf module
`src/plugins/provider-claude-thinking.ts` whose only imports are
`@openclaw/llm-core` and the existing leaf `provider-thinking.types`.
`provider-model-shared.ts` continues to re-export both helpers so existing
consumers (`extensions/anthropic/*`, the public test surface) are
unaffected. `auto-reply/thinking.ts` now imports the leaf directly,
breaking the cycle.
* test(thinking): add live proof harness for #91975 anthropic-messages clamp
---------
Co-authored-by: wanglu241 <wanglu241@jd.com>
Allow an explicit canonical ClickClack enable/setup selection to record ClickClack in a nonempty plugin allowlist, while preserving unrelated allowlist rejection, denylist authority, and global plugin disablement.
Validated at source head 24af9d8e75 with focused regressions, built-CLI disposable-config E2E, security checks, and autoreview. Merged under owner authorization despite the two documented untouched-main agent-core baseline failures.
Gemma 4 models via openai-completions (vLLM, OpenRouter, etc.) were
silently losing in-turn reasoning_content during multi-turn tool replay.
Unlike DeepSeek/Xiaomi which 400 on the missing field, these providers
accept the request but produce degraded tool-call quality — arguments
collapse to {} and identical tool calls repeat.
Root cause: two places explicitly excluded Gemma 4 from reasoning replay:
1. shouldTrustReasoningContentReplayMetadata() in openai-transport-stream
skipped Gemma 4 by model ID, causing sanitizeCompletionsReasoningReplayFields
to strip reasoning_content before sending.
2. buildOpenAICompatibleReplayPolicy() in provider-replay-helpers forced
dropReasoningFromHistory=true for Gemma 4, discarding reasoning blocks
during history sanitization before they reached the transport layer.
Remove both exclusions. Gemma 4 on non-OpenAI providers now preserves
in-turn reasoning through the existing provider/metadata checks that
already gate this correctly for other reasoning models.
Co-authored-by: wangyk <prowangyankun@foxmail.com>
Allow explicitly enabled installed plugins to register declared trusted tool policies and agent tool result middleware, with trusted policy ids scoped by plugin owner.\n\nVerification covered targeted plugin/agent tests, typecheck, build, lint, local autoreview, and a Blacksmith Testbox runtime proof (tbx_01ktr1nq0rhq47fjkwrepm7fd3).
Restores the Codex/OpenAI usage line in status by routing Codex-harness usage through the Codex app-server provider hook. Preserves configured app-server startup options, selected OpenAI/Codex auth profiles, weekly-window cadence, and Codex credit wording while skipping unsupported API-key usage probes. Fixes#91694.
Move Zalo hosted outbound media metadata and expiry into plugin state, add SDK chunked hosted media storage, and keep CI/type/lint gates green after rebase.
Fix MiniMax-M3 Anthropic-compatible requests so OpenClaw no longer sends the disabled-thinking payload that makes M3 return empty content. M3 defaults now stay on MiniMax's omitted/adaptive thinking path, explicit `/think off` is still respected, and MiniMax-M2.x keeps the disabled-thinking default that prevents reasoning_content leaks.
Also wires the MiniMax thinking policy through bundled provider-policy loading so pre-runtime and configless embedded-agent paths resolve the same defaults.
Thanks @IamVNIE for the live MiniMax API repro and initial patch.
Gateway startup now includes plugin owners for explicit memorySearch.provider and memorySearch.fallback values, including custom models.providers API owners and generic embedding provider contracts.
Sentinel and disabled paths keep existing startup behavior for auto, local, none, disabled memory search, and disabled memory slots.
Adds post-runtime-load diagnostics for configured memory embedding providers that remain unregistered.
Closes#89651
Co-authored-by: Joseph Krug <5925937+joeykrug@users.noreply.github.com>
- New extensions/parallel package modeled on extensions/exa
- Wires Parallel's POST /v1/search through the generic web_search contract,
exposing Parallel's recommended {objective, search_queries} shape (plus
optional count, session_id, client_model) so the model can supply both the
natural-language goal and 2-3 short keyword queries as Parallel docs advise
- client_model lets the model report its own slug so Parallel can tailor
optimizations for the consuming model's capabilities; partitions the cache
by client_model so different models do not silently share ranked excerpts
- Honors top-level tools.web.search.{maxResults,timeoutSeconds,cacheTtlMinutes}
via the shared SDK helpers (mergeScopedSearchConfig, withTrustedWebSearchEndpoint,
buildSearchCacheKey, read/writeCachedSearchPayload)
- Auto-detect order 75; auth via PARALLEL_API_KEY or
plugins.entries.parallel.config.webSearch.apiKey
- Optional baseUrl override for proxies (e.g. Cloudflare AI Gateway)
- Threads caller-supplied session_id through follow-up calls; strips
auto-generated session_id from the shared cache to avoid cross-task leaks
- Always sends advanced_settings.max_results so result volume matches the
OpenClaw web_search default (5) instead of Parallel's default (10)
- Identifies the plugin via User-Agent header built from package version
- Runtime accepts the generic `query` arg as a fallback so the operator
CLI (openclaw capability web.search) keeps working when Parallel is the
active provider: it is promoted into the lone `search_queries` entry.
`objective` stays optional and is never synthesized from a keyword
query (Parallel documents it as natural-language intent). Agent callers
using the native objective+search_queries shape take precedence; the
schema still advertises only the native keys
- Updates the agent tool-display extractor (src/agents/tool-display-common.ts)
to recognize Parallel's objective+search_queries shape so calls render with
query context in CLI progress and Codex activity metadata
- Adds /tools/parallel-search docs page, web.md provider listing, docs nav,
labeler entry, per-plugin registration contract test, and minimal core
touch-points (legacy migrate, registration cases, providers contract list,
runtime bundled list, vitest extension paths)