Commit Graph

67697 Commits

Author SHA1 Message Date
miorbnli
feba78fc8f fix(sessions): fail fast on non-serializable JSONL root values (#97356)
serializeJsonlLine returned JSON.stringify(entry) without guarding the
undefined return case. When the root value is undefined, a function, or a
symbol, JSON.stringify returns undefined, which serializeJsonlEntry's template
literal coerced to the literal string "undefined" and wrote to disk. That is
not valid JSON, so parseJsonlEntries silently skipped the line — a fail-silent
loss of a transcript entry with no error log.

Throw a TypeError instead so the caller fixes the bad value before it reaches
the file. Circular references and BigInt already throw via JSON.stringify and
are unaffected. Null, primitives, and plain objects are unchanged.

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-28 10:47:24 -07:00
Ben.Li
a5379472f7 feat(onboard): show setup timeline note (#97482)
* feat(onboard): show setup timeline note

* test(agents): stabilize retained lock CI flakes
2026-06-28 10:47:11 -07:00
wangmiao0668000666
2e5e5e5af9 fix(media-understanding): append actionable install hint when media provider is missing (#97484)
Gates the install hint on the official external provider catalog's
`mediaUnderstandingProviders` contract so only true media-provider
packages (e.g. groq) emit the actionable hint; channel-only ids (e.g.
feishu) and providers without a media-understanding contract (e.g.
amazon-bedrock) fall back to the legacy bare error message verbatim.

Also tightens the gateway recovery wording from generic 'restart the
gateway' to 'stop and start the gateway service' per the canonical
issue reporter's actual recovery flow (full systemd stop/start, not
hot-reload).

Co-authored-by: wangmiao0668000666 <wangmiao0668000666@users.noreply.github.com>
2026-06-28 10:45:44 -07:00
ly-wang19
4a0cd56139 fix(ui): roll formatTokens over to "M" instead of rendering "1000k" (#96298)
* fix(ui): roll formatTokens over to "M" instead of rendering "1000k"

formatTokens picks the kilo branch on the raw value (< 1_000_000), then renders
Math.round(tokens/1000). For 999_500..999_999 that rounds to 1000, producing the
nonsensical "1000k" instead of rolling over to the M branch. Re-check the rounded
kilo value and fall through to "M" when it reaches 1000, matching the sibling
formatCompactTokenCount.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci: retry — server-startup-session-migration timeout is main-branch flake, unrelated to formatTokens

---------

Co-authored-by: ly-wang19 <ly-wang19@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 10:45:12 -07:00
Masato Hoshino
949b1af433 fix(status): distinguish runtime-loaded plugins from installed inventory (#97479)
* fix(status): distinguish runtime-loaded plugins from installed inventory

/status plugins merged disk-scan plugin records with the active runtime
registry, so the detailed Loaded: list could include plugins that were
installed/config-enabled but never loaded at runtime. Record the runtime-
loaded plugin ids on the health snapshot, carry them through the merge, and
make Loaded: reflect runtime-confirmed plugins; show installed/discovered
plugins that are not active as a neutral "Installed (not active)" inventory
line rather than an error.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(status): include pinned runtime registries in loaded ids

Build runtimeLoadedPluginIds from all live runtime registry surfaces via
collectLivePluginRegistries() (active plus any pinned channel / http-route /
session-extension registry) and render Loaded: from that id set directly, so a
plugin live only through a pinned surface still counts as loaded instead of
being dropped or misreported as "Installed (not active)".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 10:44:56 -07:00
NIO
c0883a531d fix(openrouter): bound generation-cost JSON response reads (#97490) 2026-06-28 10:44:36 -07:00
NIO
0d59280131 fix(deepinfra): bound video generation JSON response reads (#97486) 2026-06-28 10:44:28 -07:00
Gio Della-Libera
102a65477e Add marketplace feed refresh command (#96155)
Merged via squash.

Prepared head SHA: 1614070e92
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Reviewed-by: @giodl73-repo
2026-06-28 10:29:15 -07:00
mushuiyu886
891096926e fix(opencode): restore Zen model catalog (#92495)
* fix(opencode): restore Zen model catalog

* fix(opencode): restore Zen transport routing

* fix(opencode): broaden Zen fallback catalog

* fix(opencode): correct Zen family routing

* fix(opencode): route Zen MiniMax through Anthropic

* fix(opencode): filter Zen live-only catalog rows

* fix(opencode): route MiniMax through Zen chat completions

* fix(opencode): omit unverified Zen model costs

* fix(opencode): align sampled Zen costs

* fix(opencode): keep Zen cost metadata required

* fix(opencode): keep Zen docs examples resolvable

* fix(opencode): move Zen catalog to provider discovery

* test(opencode): cover Zen discovery cache isolation

* fix(opencode): add Zen GLM-5.2 catalog coverage

* test(opencode): detect Zen catalog drift

Signed-off-by: sallyom <somalley@redhat.com>

---------

Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: sallyom <somalley@redhat.com>
2026-06-28 12:32:44 -04:00
xingzhou
27c1685f10 fix(agent): bound proxy error response parsing (#97351) 2026-06-28 11:53:09 -04:00
Alix-007
2f851ecfe9 fix(speech): bound TTS response reads (#96874) 2026-06-28 10:57:25 -04:00
Gio Della-Libera
70e0fd4d8b Add hosted catalog config profiles (#95981)
Merged via squash.

Prepared head SHA: ef4d81cd08
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Reviewed-by: @giodl73-repo
2026-06-28 07:53:32 -07:00
Alix-007
25e184aeab fix(minimax): bound video control response reads (#96889)
* fix(minimax): bound image/video success response reads

MiniMax image generation and video generation (task submit + status poll)
read their success responses through unbounded `await response.json()`, so
a misbehaving or hostile endpoint could stream an arbitrarily large body
into memory before parsing and exhaust the process. Read those success
bodies through the shared bounded reader (16 MiB cap, the same limit other
bundled providers and the sibling MiniMax web-search provider already use)
and cancel the stream on overflow. The error-body path is already bounded
via assertOkOrThrowHttpError; this closes the matching success-JSON gap.
MiniMax TTS is already bounded and is left unchanged.

AI-assisted.

* fix(minimax): bound video metadata response reads

* fix(minimax): leave image response sizing to image hardening

* fix(minimax): bound image/video success response reads

MiniMax image generation and video generation (task submit + status poll)
read their success responses through unbounded `await response.json()`, so
a misbehaving or hostile endpoint could stream an arbitrarily large body
into memory before parsing and exhaust the process. Read those success
bodies through the shared bounded reader (16 MiB cap, the same limit other
bundled providers and the sibling MiniMax web-search provider already use)
and cancel the stream on overflow. The error-body path is already bounded
via assertOkOrThrowHttpError; this closes the matching success-JSON gap.
MiniMax TTS is already bounded and is left unchanged.

AI-assisted.

* fix(minimax): bound video metadata response reads
2026-06-28 10:52:33 -04:00
Alix-007
9241b9701d fix(mattermost): bound successful REST JSON/text response reads (#96033)
* fix(mattermost): bound successful REST JSON/text response reads

The Mattermost REST client already bounds error bodies
(readResponseTextLimited) and streams guarded responses without buffering,
but the success path still called `await res.json()` / `await res.text()`,
reading the whole body into memory before parsing. A self-hosted or
compromised Mattermost server can return an arbitrarily large (or
never-terminating, content-length-less) JSON/text body and force the plugin
to buffer it unbounded.

Read successful JSON through the shared readProviderJsonResponse (16 MiB cap,
cancels the stream and throws a bounded error on overflow, same as the
provider HTTP path) and cap non-JSON success bodies with readResponseTextLimited.
uploadMattermostFile's file-info JSON is bounded the same way.

Symmetric follow-up to the #95103 / #95108 response-limit campaign.

AI-assisted.

* fix(mattermost): bound probe success JSON reads

* fix(mattermost): reject oversized success text bodies
2026-06-28 10:40:32 -04:00
Josh Lehman
b5e9179063 docs: deprecate legacy session file helpers (#97494)
* docs: deprecate legacy session file helpers

* docs: update sdk deprecation budgets
2026-06-28 07:33:34 -07:00
Alix-007
d577cb2fe9 fix(nextcloud-talk): bound external send/reaction response reads to prevent OOM (#96031)
* fix(nextcloud-talk): bound external send/reaction response reads to prevent OOM

Nextcloud Talk talks to self-hosted servers whose HTTP responses are not
trusted to be small. The send and reaction paths buffered three external
bodies without any byte cap:

- success JSON via await response.json()
- send error text via await response.text()
- reaction error text via await response.text()

A hostile or misbehaving Nextcloud endpoint could stream an unbounded body
(no content-length) into memory, pressuring or hanging the plugin/provider
path. Cap success JSON at 16 MiB via readResponseWithLimit and collapse error
bodies to an 8 KiB readResponseTextSnippet, cancelling the stream on overflow.
The 'message sent but receipt JSON unreadable -> unknown' fallback is
preserved (an over-limit body now also routes through the existing catch).

This is the symmetric counterpart to the #95103/#95108 response-limit
campaign, reusing the shared @openclaw/media-core helpers (newly re-exported
from plugin-sdk/response-limit-runtime for plugin consumers).

* fix(nextcloud-talk): bound error bodies via public readResponseTextLimited (no new plugin-SDK surface)

Re-exporting readResponseTextSnippet from plugin-sdk/response-limit-runtime
pushed the public plugin-SDK export count past its surface budget, failing
plugin-sdk-surface-report.test.ts. Drop that re-export and instead bound the
Nextcloud Talk send/reaction error bodies through the already-public
readResponseTextLimited (openclaw/plugin-sdk/provider-http), collapsing the
bounded 8 KiB prefix to a short, log-safe snippet locally. Behavior is
unchanged for callers; no new plugin-SDK surface is introduced.

Success JSON still reads through readResponseWithLimit (16 MiB cap). The
committed bounded-response-reads Vitest suite continues to prove the caps
hold against 17 MiB streamed bodies with no content-length.

* fix(nextcloud-talk): reuse shared readProviderJsonResponse for send success JSON

The send success receipt parsed JSON by hand via readResponseWithLimit + a
local NEXTCLOUD_TALK_JSON_MAX_BYTES cap + JSON.parse(TextDecoder.decode(...)),
duplicating the shared provider-http helper that the sibling room-info.ts and
bot-preflight.ts already use. extensions/AGENTS.md forbids re-implementing
shared helpers locally.

Swap the hand-rolled block for the one-stop
readProviderJsonResponse<{ ocs?: ... }>(response, "Nextcloud Talk send"), which
reads through the same bounded reader and throws on overflow/malformed JSON, so
the outer try/catch still keeps the "unknown" receipt and behavior is
equivalent. The error path keeps readResponseTextLimited (text, not JSON).
2026-06-28 10:30:17 -04:00
Alix-007
f1e4980a97 fix(embedding): bound OpenAI-compatible embedding response reads (#96868)
* fix(embedding): bound OpenAI-compatible embedding response reads

* test(embedding): avoid loop-condition lint in stream proof
2026-06-28 10:28:03 -04:00
Alix-007
2d2a50c00d fix(discord): bound REST response body to prevent OOM flood (#95412)
The Discord REST main response path read the body with an unbounded
await response.text() before JSON-parsing it. A controlled or hijacked
endpoint could stream an arbitrarily large body and exhaust memory (OOM).

Wrap the read in the canonical readResponseWithLimit helper with an 8 MiB
cap (well above any legitimate Discord JSON payload) plus an idle timeout
tied to the request timeout, so the stream is cancelled at the cap or on
stall instead of buffering unbounded. Normal payloads still parse fully.

This mirrors PR #95108 which bounded the analogous Anthropic Messages
error-response read with the same helper.
2026-06-28 10:20:37 -04:00
xingzhou
4d292caaa4 fix(plugin-sdk): follow paginated live model catalogs (#97012)
* fix(plugin-sdk): follow paginated live model catalogs

* fix(plugin-sdk): bound paginated live catalog discovery

* fix(plugin-sdk): reject incomplete live catalog pagination

* fix(plugin-sdk): resolve live catalog next links after redirects

* fix(plugin-sdk): preserve redirect auth boundary in catalog pagination
2026-06-28 10:08:36 -04:00
Dallin Romney
08d15ec32d test: stabilize startup session migration flake (#97370)
* test: stabilize startup session migration flake

* test: cover voice call doctor session ids
2026-06-28 04:29:41 -07:00
Dallin Romney
39c4c02653 test: link Tool Search gateway QA coverage (#97374) 2026-06-28 04:28:32 -07:00
snowzlmbot
8d168c836a fix(agents): preserve structured tool result visible text (#97268)
* fix(agents): preserve structured tool result visible text

* fix(agents): address structured tool result review blockers

* fix(agents): cover real structured tool result shapes

* fix(agents): preserve canonical tool error statuses

* fix(agents): harden structured result rendering

* fix(agents): preserve typed structured results

* fix(agents): bound provider result media

---------

Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
2026-06-28 02:38:43 -07:00
xydt-tanshanshan
d17b970bb5 [AI] fix(plugins): recognize document-extractors as a capability kind… (#91597)
* [AI] fix(plugins): recognize document-extractors as a capability kind in inspect-shape

PluginCapabilityKind did not include "document-extractors", causing
plugins that declare contracts.documentExtractors (like document-extract)
to show capabilityCount=0 and shape="non-capability" in plugins inspect.

Add "document-extractors" to PluginCapabilityKind and read from
plugin.contracts.documentExtractors in buildPluginCapabilityEntries().

Related to #91539

* [AI] test(plugins): add document-extractors shape contract coverage

Add a test case verifying that plugins declaring
contracts.documentExtractors are classified as
plain-capability shape with capabilityCount=1
and capabilities including the document-extractors kind.

Addresses ClawSweeper P2 review finding on PR #91597.

* [AI] chore: rebase on main to refresh CI

* test(plugins): fold extractor into shape matrix

---------

Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
2026-06-28 02:06:10 -07:00
NIO
38ddcef78f Fix/zalo bound api json response reads (#97277)
* fix(zalo): bound Bot API JSON response reads via readProviderJsonResponse

* test(zalo): keep API proof in focused coverage

---------

Co-authored-by: NIO <nocodet@mail.com>
Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
2026-06-28 02:04:22 -07:00
NIO
7ba9212665 Fix/discord bound probe getme json reads (#97278)
* fix(discord): bound probe getMe JSON response reads

* test(discord): add oversized probe getMe JSON regression

* test(discord): add loopback proof for bounded probe getMe reads

* fix(scripts): satisfy oxlint in discord probe proof script

* test(discord): keep probe proof in focused coverage

---------

Co-authored-by: NIO <nocodet@mail.com>
Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
2026-06-28 01:57:20 -07:00
Peter Lee
6c7a6ff1c4 fix(cron): propagate cleanupCliLiveSessionOnRunEnd to isolated cron CLI branch (#97227)
* fix(cron): propagate cleanupCliLiveSessionOnRunEnd to isolated cron CLI branch

* test(cron): add CLI interim retry coverage for isolated cron cleanup flag

Verify cleanupCliLiveSessionOnRunEnd is passed on both the initial and
retry CLI runs during isolated cron interim-ack retry loops. Proves the
inner boundary is safe: each runCliAgent call creates a fresh context,
so cleanup cannot affect the retry's live session.

* fix(cron): remove unused variable in interim retry test

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(cron): trim redundant cleanup retry coverage

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
2026-06-28 01:55:56 -07:00
Bek
9c95abd49d fix: seed Slack thread context after reset (#97100) 2026-06-28 02:36:53 -04:00
Dallin Romney
119dc4bd82 test: promote OpenAI HTTP QA coverage (#97369) 2026-06-27 22:28:31 -07:00
Dallin Romney
69af58ba26 ci: log macOS Swift build phases (#97151) 2026-06-27 22:06:56 -07:00
Galin Iliev
c6ade83a5c fix: avoid stale dashboard child context budgets (#97332)
* fix(gateway): avoid stale child session context tokens

* fix(gateway): avoid stale child session context tokens

---------

Co-authored-by: Galin Iliev <Galin.Iliev@microsoft.com>
2026-06-27 21:31:18 -07:00
Josh Avant
07b934901a fix: scanned PDF pages reach chat vision models (#97354)
* fix: forward scanned PDF page images to chat models

* fix: remove stale reply option cast
2026-06-27 23:01:08 -05:00
Gio Della-Libera
1b0766080a Add hosted catalog source profile validation (#95969)
Merged via squash.

Prepared head SHA: 6dc6ca154c
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Reviewed-by: @giodl73-repo
2026-06-27 20:56:54 -07:00
Andy Ye
830467bc93 fix(imessage): stage remote media for plugin claims (#91803) 2026-06-27 19:36:21 -07:00
Gio Della-Libera
d1b917120a Persist hosted catalog snapshots in state (#95964)
Merged via squash.

Prepared head SHA: 372ec63c99
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Reviewed-by: @giodl73-repo
2026-06-27 19:01:22 -07:00
Dallin Romney
78f7de01c1 test: link local e2e qa coverage wrappers (#97150) 2026-06-27 18:34:36 -07:00
Gio Della-Libera
3630d502eb Doctor: expose gateway runtime findings (#97075)
* feat(doctor): expose gateway runtime findings

* fix(doctor): redact gateway health targets
2026-06-27 17:17:49 -07:00
Dallin Romney
7bbd09047b docs: simplify macOS app overview (#97120)
* docs: simplify macOS app docs

* docs: preserve macOS app detail links

* docs: address macOS review feedback
2026-06-27 16:04:30 -07:00
Shakker
c53dbcaf4d fix: surface delegated Testbox proof status 2026-06-27 23:53:53 +01:00
Shakker
461e551e85 test: clarify delegated Testbox proof status 2026-06-27 23:53:52 +01:00
Galin Iliev
dc575d148a fix: page sessions_history beyond truncated tails (#97101)
* Add sessions history offset pagination

* Fix sessions_history pagination after tool caps

* Fix sessions_history PR CI blockers

* Update sessions_history prompt snapshots

* Fix offset history projection windows

---------

Co-authored-by: Galin Iliev <5711535+galiniliev@users.noreply.github.com>
2026-06-27 15:30:49 -07:00
Gio Della-Libera
12685ee6b7 Add hosted catalog snapshot fallback (#95877)
Merged via squash.

Prepared head SHA: 5f71635bba
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Reviewed-by: @giodl73-repo
2026-06-27 15:26:49 -07:00
Gio Della-Libera
36722014ef Doctor: expose configured plugin install findings (#96171)
* feat(doctor): expose configured plugin install findings

* fix(doctor): satisfy configured plugin mapper lint
2026-06-27 14:18:50 -07:00
zengLingbiao
1b8b8500ce fix(auto-reply): truncate user-facing text on UTF-16 boundary (#97299)
Summary:
- The PR imports `truncateUtf16Safe` and uses it for the Codex usage-limit preview and verbose working-label truncation paths in auto-reply.
- PR surface: Source +2. Total +2 across 2 files.
- Reproducibility: yes. Current main uses raw `slice(0, N)` at both reported user-facing truncation sites, and ... ludes terminal before/after output showing dangling surrogates before the fix and safe truncation after it.

Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.

Validation:
- ClawSweeper review passed for head 74a0a32ed9.
- Required merge gates passed before the squash merge.

Prepared head SHA: 74a0a32ed9
Review: https://github.com/openclaw/openclaw/pull/97299#issuecomment-4820038635

Co-authored-by: zenglingbiao <zeng.lingbiao@xydigit.com>
Approved-by: takhoffman
2026-06-27 20:39:32 +00:00
Gio Della-Libera
c29e1fe764 Add hosted external catalog feed loader (#95868)
Merged via squash.

Prepared head SHA: 76da9328af
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Reviewed-by: @giodl73-repo
2026-06-27 13:20:05 -07:00
Ayaan Zaidi
c52adf7505 test(telegram): cover retained preview chunk gaps 2026-06-27 12:30:57 -07:00
Ayaan Zaidi
199700de26 fix(telegram): replay retained preview gaps 2026-06-27 12:30:57 -07:00
Hannes Rudolph
b14a95b3fd docs: revert v2026.6.9 changelog update (#97306)
This reverts commit ebf1ba70d5.
2026-06-27 13:04:51 -06:00
Hannes Rudolph
ebf1ba70d5 docs: update changelog for v2026.6.9 (#97124) 2026-06-27 12:37:53 -06:00
Hannes Rudolph
78d70230b6 docs: align v2026.6.10 changelog heading (#97297) 2026-06-27 12:37:24 -06:00
shengting
98ed83f848 fix(model-fallback): don't rethrow provider-side AbortErrors as user cancellations (#90908)
* fix(model-fallback): don't rethrow provider-side AbortErrors as user cancellations

When the LLM API closes the connection mid-stream, the fetch layer
surfaces AbortError("This operation was aborted") with no external
abort signal triggered. The old guard `shouldRethrowAbort()` returned
false for these errors (because isTimeoutError matched the message),
so they fell through to the fallback loop but were never retried —
the error propagated up and produced SILENT_REPLY_TOKEN in group
sessions, permanently silencing the topic.

Replace the guard with a direct check: only rethrow AbortError when
the external abort signal is actually set (user/gateway cancellation).
Provider-side AbortErrors without an external signal now fall through
to the next fallback candidate, giving the system a chance to recover.

* fix(cron): forward abort signal into runWithModelFallback

Thread the cron executor's abort signal into the shared
runWithModelFallback call so that cron timeouts and cancellations
stop the fallback chain instead of retrying with the next candidate.

Previously, the run callback checked params.abortSignal?.aborted and
threw, but runWithModelFallback itself had no signal — so the new
guard in model-fallback.ts could not distinguish a caller abort from
a provider-side AbortError and would retry silently.

Also adds a focused regression test verifying the signal is forwarded.

---------

Co-authored-by: Shengting Xie <shengting@openclaw.ai>
Co-authored-by: yayu <yayu@yayuMacStudio.local>
2026-06-27 20:53:16 +03:00