fix(twitch): strip internal tool-trace banners from outbound text - #103109
Conversation
|
Codex review: passed. Reviewed July 9, 2026, 5:15 PM ET / 21:15 UTC. Summary PR surface: Source +4, Tests +33. Total +37 across 2 files. Reproducibility: yes. Source-level reproduction is high confidence: current main and Review metrics: none identified. Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Next step before merge
Security Review detailsBest possible solution: Land this narrow Twitch adapter hook after exact-head automerge checks pass, while keeping the umbrella issue open for the remaining channel slices or any later shared-default decision. Do we have a high-confidence way to reproduce the issue? Yes. Source-level reproduction is high confidence: current main and Is this the best way to solve the issue? Yes. The existing outbound adapter hook is the narrow owner-boundary fix and matches merged sibling channels; a shared global default would be a broader product-contract change for the umbrella issue. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against ae11ea5ba9a0. Label changesLabel justifications:
Evidence reviewedPR surface: Source +4, Tests +33. Total +37 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (1 earlier review cycle)
|
|
🦞🔧 Repair: kept the fix on this contributor branch instead of opening a replacement PR. Current state: exact-head review queued immediately; GitHub checks and the review verdict gate final merge. Automerge progress:
|
Co-authored-by: Masato Hoshino <246810661+masatohoshino@users.noreply.github.com>
5dad685 to
3f69bfe
Compare
…enclaw#103109) * fix(twitch): strip internal tool-trace banners from outbound text Co-authored-by: Masato Hoshino <246810661+masatohoshino@users.noreply.github.com> * fix(twitch): strip internal tool-trace banners from outbound text --------- Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com> Co-authored-by: Masato Hoshino <246810661+masatohoshino@users.noreply.github.com>
…text The Nextcloud Talk outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered chat messages. The same one-line sanitizeText hook was already shipped to 13 sibling channels (mattermost openclaw#98693, feishu openclaw#98705, twitch openclaw#103109, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text) to the outbound base adapter, matching those precedents. Co-Authored-By: Claude <noreply@anthropic.com>
The Nostr outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Nostr DMs. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText to the NostrOutboundAdapter type and adapter, matching those precedents. Co-Authored-By: Claude <noreply@anthropic.com>
The Zalo outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Zalo messages. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text) to the outbound adapter, matching those precedents. Co-Authored-By: Claude <noreply@anthropic.com>
The Nostr outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Nostr DMs. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText to the NostrOutboundAdapter type and adapter, matching those precedents. Co-Authored-By: Claude <noreply@anthropic.com>
The Zalo outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Zalo messages. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text) to the outbound adapter, matching those precedents. Co-Authored-By: Claude <noreply@anthropic.com>
The Zalo outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Zalo messages. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text) to the outbound adapter, matching those precedents. Co-Authored-By: Claude <noreply@anthropic.com>
The Nostr outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Nostr DMs. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText to the NostrOutboundAdapter type and adapter, matching those precedents. Co-Authored-By: Claude <noreply@anthropic.com>
The Nostr outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Nostr DMs. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText to the NostrOutboundAdapter type and adapter, matching those precedents. Co-Authored-By: Claude <noreply@anthropic.com>
The Zalo outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Zalo messages. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text) to the outbound adapter, matching those precedents. Co-Authored-By: Claude <noreply@anthropic.com>
The Zalo outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Zalo messages. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text) to the outbound adapter, matching those precedents. Co-Authored-By: Claude <noreply@anthropic.com>
The Nostr outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Nostr DMs. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText to the NostrOutboundAdapter type and adapter, matching those precedents. Co-Authored-By: Claude <noreply@anthropic.com>
The Nostr outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Nostr DMs. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText to the NostrOutboundAdapter type and adapter, matching those precedents. Co-Authored-By: Claude <noreply@anthropic.com>
The Nostr outbound adapter had no sanitizeText hook, so internal assistant tool-trace scaffolding (e.g. "⚠️ 🛠️ `exec (agent)` failed", raw <tool_call>/<function_response> XML) leaked verbatim into delivered Nostr DMs. The same one-line sanitizeText hook was already shipped to 13 sibling channels (twitch openclaw#103109, mattermost openclaw#98693, feishu openclaw#98705, signal openclaw#97360, slack openclaw#97367, matrix openclaw#97372, irc openclaw#97214, telegram, googlechat openclaw#90684, qqbot openclaw#90132, discord, whatsapp openclaw#71830, sms). Add sanitizeText to the NostrOutboundAdapter type and adapter, matching those precedents. Co-Authored-By: Claude <noreply@anthropic.com>
* fix(wiki): wiki_get and wiki compile miss nested source files (#96022)
* fix(wiki): discover nested source files in QUERY_DIRS
Two functions in the memory-wiki extension — listWikiMarkdownFiles
(wiki_get runtime lookup) and collectMarkdownFiles (wiki compile
indexing) — used fs.readdir without { recursive: true }. Nested
source files (e.g. sources/audi/car.md) were silently invisible to
both wiki_get and wiki compile.
Add recursive: true and adjust path construction using
entry.parentPath so nested .md files in all QUERY_DIRS are
discovered while preserving the index.md exclusion and backward
compatibility with flat vaults.
* fix(wiki): remove entry.path fallback, only parentPath is typed on Dirent
* fix(wiki): add recursive scan to status.ts and add nested-file regression tests
* fix(wiki): use toSorted instead of sort to pass lint
* style(memory-wiki): format recursive discovery fix
---------
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
(cherry picked from commit 63ee4cd2405c932f338de269147ed0510910c0e8)
* fix(tools-manager): require clean exit in commandExists (#96361)
Summary:
- The PR changes the agent tools manager to treat spawned-but-nonzero fd/rg probes as missing and adds regression tests for non-zero and zero spawn status.
- PR surface: Source +3, Tests +27. Total +30 across 2 files.
- Reproducibility: yes. Current main ignores non-zero `spawnSync.status`, and a live Node probe confirms a spawned child can exit non-zero while leaving `error` unset.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 377d560effe8fbeaf464bcdf8f5892eab925475a.
- Required merge gates passed before the squash merge.
Prepared head SHA: 377d560effe8fbeaf464bcdf8f5892eab925475a
Review: https://github.com/openclaw/openclaw/pull/96361#issuecomment-4788071605
Co-authored-by: liyuanbin <li.yuanbin1@xydigit.com>
Co-authored-by: Claude <noreply@anthropic.com>
Approved-by: takhoffman
(cherry picked from commit 380f2749becc001c4f949a922d9a0fd427e2b539)
* fix(lmstudio): bound model load success response body to prevent OOM (#96042)
The /api/v1/models/load success path read the response with an unbounded
await response.json(), so a misbehaving or compromised LM Studio server
could stream an arbitrarily large JSON body that is fully buffered into
memory before any size check. Read it through the shared byte-capped
readProviderJsonResponse helper instead (16 MiB provider-JSON cap, cancels
the stream on overflow, wraps malformed JSON), matching the discovery path
and the already-bounded error body.
Migrate the model fetch/load test mocks to real Response objects (the
bounded readers need a real body stream) and add a regression test that
streams an oversized success body and asserts a bounded error plus stream
cancellation.
Label: security
(cherry picked from commit 7844b0844568f8f71040008ef596bc715064657b)
* fix(parallel): bound successful web-search JSON response reads (#96035)
* fix(parallel): bound successful web-search JSON response reads
The Parallel web_search provider parsed its /v1/search success body with an
unbounded await res.json(). The body comes from an external web-search
upstream, so a hostile or malfunctioning endpoint streaming an unbounded JSON
payload could force the runtime to buffer the whole response before parsing,
creating memory pressure or a hang on the provider path.
Read the success body through the shared readProviderJsonResponse helper with a
16 MiB cap (matching the provider JSON cap from #95218); on overflow the stream
is cancelled and a bounded error is thrown. The error-body path was already
bounded (readResponseTextLimited, 8 KiB). Symmetric follow-up to the
#95103/#95108 response-limit campaign.
* docs(parallel): drop upstream PR ref from response-cap comment
Replace the PR-specific '#95218' annotation with a neutral description of
the shared provider JSON cap so the comment stays accurate independent of
upstream PR numbering.
(cherry picked from commit 6163b1977b4d8703c41fadc99f4ab9bc36a38772)
* fix(exa): bound untrusted search JSON response reads (#96038)
Exa search success responses were read via an unbounded `await
response.json()`, so a misbehaving or hostile endpoint could stream an
arbitrarily large body into memory before parsing. Read the success
body through the shared bounded reader (16 MiB cap, the same limit other
bundled providers use) and cancel the stream on overflow. This mirrors
the error-body bound already in place and the #95103/#95108 response
-limit campaign on the success-JSON side.
AI-assisted.
(cherry picked from commit 605aede38c10787e74303aec1eef696af6c1927d)
* fix(ollama): bound model-discovery JSON response reads (#96027)
* fix(ollama): bound model-discovery JSON response reads
The /api/tags and /api/show discovery reads in extensions/ollama/src/provider-models.ts
parsed their HTTP responses with an unbounded await response.json(). Ollama base URLs
are user-supplied and can point at remote/cloud endpoints, so a hostile or buggy server
(or one reachable via SSRF) could stream an unbounded or never-ending JSON body and drive
model discovery into OOM.
Route both reads through the shared @openclaw/media-core byte-bounded reader
(readResponseWithLimit, re-exported via openclaw/plugin-sdk/response-limit-runtime) under
a single 16 MiB cap before JSON.parse, cancelling the stream on overflow. Overflow throws a
bounded error that the existing fail-soft handlers swallow, so a capped endpoint degrades
gracefully: /api/tags returns { reachable: false, models: [] } and /api/show returns {}.
Symmetric counterpart to the #95103/#95108 response-limit campaign.
AI-assisted.
* fix(ollama): reuse shared bounded JSON reader for model discovery
Replace the local readOllamaDiscoveryJson helper with the shared
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http), which
already enforces the 16 MiB cap, cancels the stream on overflow, and wraps
malformed JSON with the caller label. The /api/tags and /api/show discovery
reads now go through it directly while keeping the existing fail-soft
handlers ({ reachable: false, models: [] } and {}).
Add a focused regression test: when a discovery stream exceeds the JSON byte
cap, fetchOllamaModels returns { reachable: false, models: [] },
queryOllamaModelShowInfo returns {}, and the bounded reader cancels the body
mid-flight so less than the full advertised stream is read.
(cherry picked from commit d1c2934d0d17fe2c52912b05c320654ca9fb0242)
* fix(providers): bound self-hosted provider discovery JSON reads (#95244)
* fix(providers): bound self-hosted discovery JSON reads
discoverLlamaCppRuntimeContextTokens and discoverOpenAICompatibleLocalModels
parsed their HTTP responses via an unbounded await response.json(). Self-hosted
provider base URLs are user-supplied and untrusted (an endpoint reachable via
SSRF could stream an unbounded JSON body), so a hostile or buggy endpoint could
drive the setup wizard into OOM.
Route both reads through the shared byte-bounded reader (readResponseWithLimit
from @openclaw/media-core) under a single 4 MiB cap before JSON.parse, mirroring
the bound-stream hardening landed for Anthropic error bodies. Overflow cancels
the stream and is swallowed by the existing discovery error handling, so a
capped endpoint degrades gracefully (returns [] / skips the runtime context
probe) instead of buffering the whole body.
* tune self-hosted discovery cap
Signed-off-by: sallyom <somalley@redhat.com>
---------
Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: sallyom <somalley@redhat.com>
(cherry picked from commit dad5ce64d4f1ba35e8f4cff73ddd3d704d4c5898)
* fix(providers): bound successful response reads
Backport of 0a14444924e34e031133c997b00d30573353c5a0; retains the target's existing provider-reader SDK baseline.
* fix(outbound): prevent partial-send recovery replay
(cherry picked from commit 210ea659f77f3b600043952a5686e640311846e3)
* fix(qwen): bound video success response (#96604)
(cherry picked from commit cc124d2921b88d241a567f17368bd55049d84f83)
* fix(byteplus): bound video-generation success response (#96606)
(cherry picked from commit 7b5ee739eb22b53022a5674a3bf674dc0e6c33d5)
* fix(voyage): bound embedding-batch status, error, and non-OK responses (#96608)
The batch status read (fetchVoyageBatchStatus) parsed its response with an
unbounded await res.json(), and the batch error-file read (readVoyageBatchError)
buffered the whole body via await res.text(). On top of that, the non-OK
(4xx/5xx) diagnostic body was still read unbounded: assertVoyageResponseOk did
await res.text() before throwing, and the non-OK output-file branch in
runVoyageEmbeddingBatches did the same. Voyage base URLs are user-supplied and
reachable via SSRF, so a misbehaving or hostile endpoint could stream an
unbounded body into memory on any of these paths before parsing.
Route the status JSON through the shared readProviderJsonResponse, the error
file through readResponseWithLimit, and now the non-OK diagnostic body through
readResponseWithLimit as well, all under a single 16 MiB cap, cancelling the
stream on overflow before decode/parse. assertVoyageResponseOk preserves its
original "${context}: ${status} ${text}" diagnostic shape for under-cap bodies
and throws a bounded "(error body exceeds <N> bytes)" on overflow; the non-OK
output-file branch now reuses it instead of a duplicate unbounded read. The
existing error-file fail-soft handling (formatUnavailableBatchError) is
preserved, so a capped endpoint degrades gracefully. The submit path already
bounds its body via postJsonWithRetry/maxResponseBytes and is left untouched.
Symmetric counterpart to the #96027/#96038 response-limit campaign.
(cherry picked from commit d3620da3e031b2b52414165d09315d78a13c6836)
* fix(github-copilot): bound usage response (#96607)
The Copilot usage read in extensions/github-copilot/usage.ts parsed its
HTTP response with an unbounded await res.json(). A hostile or buggy
api.github.com proxy (the proxy endpoint is derived from a user-supplied
token) could stream an unbounded JSON body and drive the usage snapshot
into OOM.
Route the read through the shared readProviderJsonResponse (from
openclaw/plugin-sdk/provider-http), which enforces the 16 MiB byte cap,
cancels the stream on overflow, and wraps malformed JSON with the caller
label. Same no-helper-import-to-bounded-reader shape as the #96027 /
#96038 response-limit work.
Add a focused regression test: when the usage stream exceeds the JSON
byte cap, fetchCopilotUsage rejects with a bounded-overflow error and the
reader cancels the body mid-flight instead of buffering the full
advertised stream. Existing parse/HTTP-error cases keep passing.
(cherry picked from commit 646e54ae3578b48259912d288d0cecfcb132a035)
* fix(openrouter): bound video catalog JSON reads (#96505)
(cherry picked from commit 5715b5500067e4af80ca40da10775de4b3648cea)
* fix(speech): bound TTS/STT voice-list and transcription JSON response reads (#96496)
Route success JSON reads through readProviderJsonResponse (16 MiB cap) in
azure-speech, elevenlabs, microsoft, minimax/tts, xai/stt, and
openrouter/media-understanding to prevent OOM from oversized or hostile
endpoint responses. Mirrors the response-limit campaign already applied to
other provider paths.
AI-assisted.
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 66e2fcc6f83eb6aef394401a19342d7af19b1478)
* fix(github-copilot): bound model discovery and embeddings JSON response (#96499)
* fix(github-copilot): bound model discovery and embeddings JSON response reads
The GitHub Copilot embeddings plugin already bounds its error response
bodies via readResponseTextLimited, but the success JSON reads for both
model discovery and the embeddings call used unbounded response.json().
Route both through readProviderJsonResponse (16 MiB cap).
Update isCopilotSetupError to recognise the new error label prefix so
auto-selection still falls through on malformed discovery responses.
Update tests to use proper Response objects and the new error messages.
AI-assisted.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(github-copilot): use memory embedding response cap
Signed-off-by: sallyom <somalley@redhat.com>
---------
Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: sallyom <somalley@redhat.com>
(cherry picked from commit 1aa7cafc35a1aaaf1cd2f9b905d6cca2603ba994)
* fix(image-gen): bound image generation provider JSON response reads (#96495)
* fix(image-gen): bound image generation provider JSON response reads
Route success JSON reads through readProviderJsonResponse (16 MiB cap)
in openrouter, google, fal, minimax, openai, and vydra image generation
providers to prevent OOM from oversized or hostile endpoint responses.
Mirrors the response-limit campaign already applied to other provider paths.
AI-assisted.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(image-gen): size bounded JSON caps for inline image payloads
Signed-off-by: sallyom <somalley@redhat.com>
---------
Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: sallyom <somalley@redhat.com>
(cherry picked from commit 527f8f0cbba1b5653dc990fd368c004f03803cf8)
* fix(google-media): bound JSON response reads (#96920)
* fix(google-media): bound JSON response reads
* test(google): relax media response cap assertion
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
(cherry picked from commit a7bfc06f4597ee946cbc066cb41750a7e8f59c52)
* fix(google): bound TTS success JSON response reads (#96984)
(cherry picked from commit 5ccfc97b319ee627bd84710ceb4cd1f81b0088f0)
* fix(clickclack): bound REST success JSON response reads (#96970)
* fix(clickclack): bound REST success JSON response reads
* test(clickclack): harden response cap proof
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
(cherry picked from commit f4fa10c2c5acae26156868fe50f01d52a464f4b1)
* 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>
(cherry picked from commit 7ba9212665a728993550a65ef5d8fdd235d4a160)
* 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>
(cherry picked from commit 38ddcef78f072d647136a1e28bf7383b0e203a37)
* 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
(cherry picked from commit f1e4980a9705dd0649946876c9a40b15d2809d24)
* 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
(cherry picked from commit 9241b9701d9c14f4d3b3a176071d95e9c21de4ac)
* 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
(cherry picked from commit 25e184aeab644b3f1acbef7f00fdd9121fe6d1a4)
* fix(speech): bound TTS response reads (#96874)
(cherry picked from commit 2f851ecfe9df4486878305798775f7e8f04fdf92)
* fix(deepinfra): bound video generation JSON response reads (#97486)
(cherry picked from commit 0d59280131c003e547264c029d6ec4590ae6e108)
* fix(openrouter): bound generation-cost JSON response reads (#97490)
(cherry picked from commit c0883a531de936174cfec903d63e6746730fccd9)
* fix(openrouter): bound video response reads
Route OpenRouter video submit and poll success JSON through the shared bounded provider JSON reader, preserving malformed-response mapping and SSRF request policy coverage.
(cherry picked from commit 48f34b1d4df7755a19894f1e763011bb8bd328ea)
* fix(signal): bound GitHub release info JSON response with readProviderJsonResponse (#97536)
Replace bare `await response.json()` in `installSignalCliFromRelease` with
`readProviderJsonResponse` (16 MiB cap, stream cancel on overflow). The
external GitHub Releases endpoint can include a large `body` changelog field;
the error path was already guarded but the success path was unbounded.
The existing inner catch continues to convert overflow errors into the
graceful `{ ok: false, error: "Failed to parse signal-cli release info." }` path.
Adds a regression test verifying the stream is cancelled before all chunks are
read on an oversized 20 MiB streaming response.
Co-authored-by: NIO <nocodet@mail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 51064bda4def47da9864c63eb0bed4e2aa614afb)
* fix(openai): bound embedding-batch and realtime session JSON response reads (#97533)
(cherry picked from commit 4c477ee6321eb628db8231ad370c7b9159d467f0)
* fix(telegram): bound getChat Bot API response reads (#97274)
* fix(telegram): bound getChat Bot API response reads
* fix(telegram): repair getChat bound-read type and proof script lint
---------
Co-authored-by: NIO <nocodet@mail.com>
(cherry picked from commit b948c86b2a834701619fb738f5bf3d0aa954f106)
* fix(google): bound embedding-batch JSON response reads (#97535)
* fix(google): bound embedding-batch JSON response reads
* fix(google): repair embedding-batch test types and lint
---------
Co-authored-by: NIO <nocodet@mail.com>
(cherry picked from commit 91297bf420822bbfd8883af157fe9d1c77774dde)
* fix(ollama): bound cloud-auth 401 JSON response reads
(cherry picked from commit a82cff8892cd7c581585254308ef7c65f6e4f9c3)
* fix(xai): bound OAuth response reads to prevent OOM (#97615)
Replace unbounded response.text() in readResponseBody and
response.json() in the device-code polling loop with
readResponseWithLimit (16 MiB cap).
(cherry picked from commit d5aca1d6d2d78e821d06d6900ae3b005e2af8942)
* fix: bound APNs relay response body so an oversized relay reply can't exhaust gateway memory
Reviewed and accepted after live preflight: mergeable clean, checks passing, no unresolved review threads.
(cherry picked from commit 89b5a879090ae693153e50586d191654a0f60113)
* fix(runway): bound video create/poll response reads
Reviewed and accepted after live preflight: mergeable clean, checks passing, no unresolved review threads.
(cherry picked from commit 63b089383adf50be175322414166f57212cc34cc)
* fix(openai): bound video create-submit response reads
Reviewed and accepted after live preflight: mergeable clean, checks passing, no unresolved review threads.
(cherry picked from commit f0e2f7b4f5ae61cf3ec08521e1c46f462ee3e6a0)
* fix(together, pixverse): bound video response reads
Reviewed and accepted after live preflight: mergeable clean, checks passing, no unresolved review threads.
(cherry picked from commit ca1bc5875913f865388f365d9906e8f8e0a5d659)
* fix(fal): bound music/video generation response reads
Reviewed and accepted after live preflight: mergeable clean, checks passing, no unresolved review threads.
(cherry picked from commit ce1217a49ca619d6e4513ac803e4b2c71e892dba)
* fix(vydra): bound control response reads
Reviewed and accepted after live preflight: mergeable clean, checks passing, no unresolved review threads.
(cherry picked from commit 74a9beb83f515c805b41d12bdeddf33b7128490f)
* fix(video-generation): bound DashScope JSON response reads
(cherry picked from commit 238398e33147338865ac957f32d8b7dc32674830)
* fix(comfy): bound JSON response reads via readProviderJsonResponse
(cherry picked from commit bf66b4e1ea7ef85e4677af2e838933efba3442e4)
* fix(github-copilot): bound login JSON response reads
(cherry picked from commit 748bea34341678cda7e664a01ee821d7a301a181)
* fix(xai): bound video response body reads
(cherry picked from commit 46e119074ef0f953b82401d08dd76e62031cf78d)
* fix(provider-usage): bound usage response body reads
(cherry picked from commit db2786bde1055fcc27b0be1243c662fbd797efbc)
* fix(agents): bound WHAM usage probe JSON response reads
(cherry picked from commit 0ce10d779302bb12f3f287bb519299a11142fb5b)
* fix(discord): bound PluralKit and voice-message JSON reads
(cherry picked from commit 597a0ba43ca3bbc35b33216abefc37449ea279ec)
* fix(nextcloud-talk): bound bot preflight error reads (#97811)
Co-authored-by: Pick-cat <266665499+Pick-cat@users.noreply.github.com>
(cherry picked from commit 09167523bf4092aba45ec7b28f4d7b1ea1d23c1b)
* fix(pdf): guard native provider requests (#97872)
* fix(pdf): guard native provider requests
* fix(pdf): preserve configured origin trust
* fix(pdf): preserve resolver compatibility
(cherry picked from commit b7b2e1f77eb4d2d58982db065642d70db50d4c8c)
* fix(cli): bound docs search API response reads with committed test (#98188)
(cherry picked from commit f284ce3b4df717dde2bbec22f840906c31bcb1f0)
* fix(moonshot): bound video description JSON response reads (#96502)
* fix(moonshot): bound video description JSON response reads
The Moonshot video description endpoint used an unbounded await res.json()
to parse the media understanding response. Route through
readProviderJsonResponse (16 MiB cap) to match the bound already in
place for other media understanding providers (xai, openrouter).
AI-assisted.
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(moonshot): add bounds and malformed-JSON coverage for video description
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 765d05c2e4a891873b782c969957c6eddc163405)
* fix(minimax): bound OAuth JSON response via shared provider reader (#96322)
Use readProviderJsonResponse (shared 16 MiB default cap) instead of
unbounded response.json() for MiniMax OAuth authorization code endpoint.
Signed-off-by: lsr911 <liao.shirong@xydigit.com>
Co-authored-by: Claude <noreply@anthropic.com>
(cherry picked from commit 4a96c066154281f2a87bb399722e3e5183ec6c71)
* fix(openai): bound embedding batch file downloads (#98554)
* fix(openai): bound embedding batch file downloads
* fix(openai): bound batch output records
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
(cherry picked from commit ce4a259485f25e238929ba1cc0c17ffbdd393554)
* fix(memory): preserve UTF-8 when qmd output splits across pipe chunks (#107263)
* fix(memory): preserve UTF-8 across fragmented qmd output chunks
* fix(memory): decode qmd streams at UTF-8 boundary
Co-authored-by: wahaha1223 <0668001153@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 7f36f490528b1466dfad05a491bd253e9cbf03f5)
* fix(synology-chat): bound outbound NAS response bodies to prevent Gateway OOM (#105089)
* fix(synology-chat): settle user_list overflow without hanging
Cap reads at 1 MiB with Buffer concat. On overflow, finish the promise
before destroy() — bare destroy often skips end/error and hung the test.
* fix(synology-chat): share bounded user-list reader
Co-authored-by: zw-xysk <zhao.wang1@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 30c257f6b45ea9002a70652fb0170ba33e3eb068)
* fix(extensions): prevent corrupted UTF-8 in api.exec output (#108365)
* fix(extensions): preserve split UTF-8 in api.exec
* test(agents): cover incomplete exec UTF-8 at EOF
Co-authored-by: zhang-guiping <zhang.guiping@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 3b51889c3bbf6801e0d523e73f2437186831ff7c)
* fix(sessions): stop leaking file path as prompt content on read failure (#108546)
* fix(sessions): stop leaking file path as prompt content on read failure
When readFileSync fails for a valid file path, resolvePromptInput returns
the raw path string as prompt content instead of undefined. This injects
filesystem paths into the LLM context. The existing console.error warning
still fires; the caller already handles undefined returns correctly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test: cover unreadable prompt paths
* test: use tracked resource loader temp dirs
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit c9248192926ac164fe4a91af3fe72555a7512c67)
* fix(clickclack): bound websocket handshake waits at 30s (#106485)
* fix(clickclack): bound websocket handshake waits at 30s
* test(clickclack): prove WebSocket handshake deadline
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 3eec404aab29e9dd78d2e69c9b4e2985f6a326fe)
* fix(memory-core): write MEMORY.md atomically during short-term promotion (#108397)
* fix(memory-core): write MEMORY.md atomically during short-term promotion
applyShortTermPromotions rewrote MEMORY.md with a single non-atomic
fs.writeFile, which truncates the file before streaming the new content.
An OS write failure part way through (for example EFBIG on a size-limited
or full volume) left MEMORY.md truncated to the bytes written before the
failure, permanently dropping user long-term memory. The dreaming cron
path invokes this writer automatically, and the recall store is only
updated after the write, so the promotion stays eligible and the next
run reads the already-truncated file.
Route the write through replaceFileAtomic (temp file, fsync, atomic
rename), the same durable-write helper the sibling DREAMS.md writer in
this extension already uses. On failure the temp file is discarded and
the existing MEMORY.md is left untouched; on success the content and the
existing file mode are preserved.
* fix(memory-core): harden atomic promotion durability
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 0317d7e628010d6e51a2a09f9d7e9af677216981)
* fix(agents): bound base64 image input before decode in tool-image sanitizer (#105086)
* fix(agents): bound base64 image input before decode in tool-image sanitizer
* fix(agents): lower input-size cap to 10MB for OOM headroom
* fix(agents): align tool-image input-cap comment with 10 MiB ceiling
* fix(agents): typecheck-safe access in tool-image input-cap test
* test(agents): exercise real tool image input cap
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit b85531c62f7565856219f652bf9fe6cfa1940b1f)
* fix(qqbot): bound tail log reads to actual bytes returned by fs.readSync (#108955)
* fix(qqbot): bound tail log reads to actual bytes returned by fs.readSync
* fix(qqbot): satisfy knip deadcode check for testing export
Add __testing re-export and test-api.ts barrel so knip traces the testing export through a recognized entry point.
* fix(qqbot): restore testing export alongside __testing re-export
Both exports are needed: testing for proof scripts, __testing for knip tracing.
* fix(qqbot): remove unused __testing re-export from log-helpers
test-api.ts already imports testing and re-exports as __testing. The extra re-export in log-helpers.ts was unused by production code.
* fix(qqbot): retry short log tail reads
* test(qqbot): keep short-read seam private
Co-authored-by: RileyJJY <100176083+RileyJJY@users.noreply.github.com>
* test(qqbot): exercise short reads through log export
Co-authored-by: RileyJJY <0668000974@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: RileyJJY <100176083+RileyJJY@users.noreply.github.com>
(cherry picked from commit 3f89aae98da9229ea7cf9bfc6215aaeae01a8796)
* fix(proxy-capture): guard body-less arrayBuffer reads against oversized responses (#101268)
* fix(proxy-capture): guard body-less arrayBuffer reads against oversized responses
* fix(proxy-capture): exercise body-less fallback in bounded read tests
New tests use mock clones with body: null plus arrayBuffer spies to
prove the content-length precheck guards the !body path. A real
Response clone exposes body.getReader in Node 24, so the prior test
only exercised the streaming branch and would stay green even if
the precheck were deleted.
* chore: retrigger CI
* fix(proxy-capture): reject non-safe content-length before arrayBuffer (#101268)
ClawSweeper P2: the body-less fallback used Number(content-length), so a
huge digit-only Content-Length value could overflow to Infinity, bypass the
Number.isFinite guard, and still call arrayBuffer() — leaving an OOM path in
the hardening PR.
Add declaredContentLengthExceedsCap, which accepts only plain digit strings,
treats any value longer than Number.MAX_SAFE_INTEGER as oversized, and
compares safe-integer parsed values against the cap. Non-numeric or malformed
values fall through to the post-read length check.
Adds a regression test for a 100-digit Content-Length that would previously
have bypassed the guard.
* fix(proxy-capture): normalize zero-padded Content-Length before digit-count guard
* fix(proxy-capture): fail closed without response streams
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 7cde0ac8c0a821e3641a3418bddad41dda6c4c7b)
* fix(lmstudio): cancel model discovery response body on non-ok (#109718)
* fix(lmstudio): cancel model discovery response body on non-ok
Wire the direct-fetch release hook to cancel unread bodies so failed
model discovery releases the TCP connection instead of leaving it open.
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor(lmstudio): unify response cleanup
Co-authored-by: Zeng Wen <27948732+ZengWen-DT@users.noreply.github.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Zeng Wen <27948732+ZengWen-DT@users.noreply.github.com>
(cherry picked from commit 1573c78f5b849d1fedf12a78aa029c069c44ffca)
* fix(msteams): cancel non-OK consent upload response body before throwing (#109701)
* fix(msteams): cancel non-OK consent upload response body before throwing
* fix(msteams): release all consent upload responses
Cancel unread response bodies after successful uploads as well as failed uploads, and fold the lifecycle assertions into the existing status-path tests.
Co-authored-by: Monkey-wusky <66244686+Monkey-wusky@users.noreply.github.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 9b238a792788474134513f7864c86dd6fd4dcd4f)
* fix(discord): honor caller abortSignal during 429 retry backoff (#109913)
* fix(discord): honor caller abortSignal during 429 retry backoff
* test(discord): prove 429 backoff abort through a real loopback server
* test(discord): make retry abort proof deterministic
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 40acbb05c9d7cf6783bb4cf4a99f332ef14cde0a)
* fix(auto-reply): treat U+2028/U+2029 as paragraph boundaries when chunking (#103518)
* fix(auto-reply): treat U+2028/U+2029 as paragraph boundaries when chunking
chunkByParagraph normalized only CR/CRLF before blank-line paragraph detection,
so model output using Unicode LINE/PARAGRAPH SEPARATOR (U+2028/U+2029) instead
of a blank line was not split at those boundaries and fell back to length-based
splitting. Normalize U+2028/U+2029 to \n alongside CR/CRLF, matching how the
Control UI markdown renderer handles them.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(auto-reply): normalize U+2028 as line break, U+2029 as blank-line paragraph boundary
Distinguish U+2028 (LINE SEPARATOR) from U+2029 (PARAGRAPH SEPARATOR):
U+2029 becomes \n\n (blank line — paragraph boundary) while U+2028
becomes \n (single newline — intra-paragraph line break).
The original fix mapped both to \n, so standalone U+2029 still
produced single-line text without a blank-line gap — paragraph
detection failed. The combined U+2028
input accidentally
produced the right blank-line sequence, which masked the bug.
Adds individual tests for lone U+2029 (splits at paragraph boundary),
lone U+2028 (stays within paragraph), and consecutive U+2028
(combined blank line — matches \n\n behavior).
* test(auto-reply): simplify Unicode separator cases
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 3a4e2ef65f418d3fdc79cebcbbd698a7aa8b9344)
* fix(synology-chat): bound user_list fetches with a wall-clock deadline (#109111)
* fix(synology-chat): bound user_list fetches with a wall-clock deadline
* refactor(synology-chat): keep deadline internal
* style(synology-chat): format deadline proof
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit f7cc0ef8380efb0d5781239458f5f5fa6688ea41)
* fix(security): bound plugin manifest reads in audit deep scan (#101773)
(cherry picked from commit aa0c92186b67c55d6f43ec6611ff689b66b65fd6)
* fix(heartbeat): bound HEARTBEAT.md file read size (#101775)
* fix(heartbeat): bound HEARTBEAT.md file read size
* fix(heartbeat): follow symlinked HEARTBEAT.md while bounding reads
* fix(heartbeat): warn operators when oversized HEARTBEAT.md is skipped
(cherry picked from commit 993c975f5738dbcd17882db0fafcb9d1e403607e)
* fix(plugins): bound marketplace manifest file reads (#101774)
* fix(plugins): bound marketplace manifest file reads
* fix(plugins): distinguish oversized marketplace manifest from other read failures
* fix(plugins): follow symlinked marketplace manifests while bounding reads
* test(plugins): cover oversized symlinked marketplace manifest target
(cherry picked from commit 35754a63ccafc41122085bc9467fd3e1dbc8d4f3)
* fix(plugins): bound plugin manifest metadata file reads (#110036)
* fix(plugins): bound plugin manifest metadata file reads
* fix(plugins): use correct Error type check in oversized manifest catch
readRegularFileSync throws a plain Error (not RangeError) when the file
exceeds maxBytes. Change the catch-block type check from RangeError to
Error to properly detect oversized plugin manifests and emit the
subsystem warning.
* test(plugins): exercise valid oversized manifests
Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 2e21d53c84ec88433dac587bb97f2796e63b20ca)
* fix(gateway): bound BOOT.md file read size (#101776)
* fix(gateway): bound BOOT.md file read size
* fix(gateway): treat non-regular BOOT.md as empty/missing and add coverage
* fix(gateway): preserve non-size BOOT.md failures while bounding oversized reads
* fix(gateway): preserve readable BOOT.md symlink behavior
* fix(gateway): treat dangling BOOT.md symlink as missing
* fix(gateway): report oversized BOOT files
* fix(gateway): preserve missing BOOT race behavior
Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit e22c2dfaaa890d1d689f894a46c6cc0a4339d301)
* fix(agents): bound IDENTITY.md reads to prevent OOM (#101447)
* fix(agents): bound IDENTITY.md reads to prevent OOM
* fix(agents): reuse shared workspace bootstrap file size limit for IDENTITY.md
* chore: retrigger CI after cancelled gate run
* chore: retrigger CI after runner tooling flake
* chore: retrigger CI after main typecheck fix and runner brew flake
* fix(identity): bound explicit --identity-file imports through shared loader
* fix(agents): unexport parseIdentityMarkdown to satisfy production deadcode scan
* chore: retrigger CI after stuck previous run
* chore: retrigger CI after stuck checks-node-compact-large-4 run
* chore: retrigger CI after stuck checks-node-compact-large-4 and flaky small-9
* fix(agents): report oversized identity file size to the user
When `--identity-file` points at a file exceeding the size limit, the
`no identity data found` error is misleading. Re-throw the fs-safe
`exceeds` error with a human-readable message so the CLI surfaces the
actual cause.
* fix(agents): update test assertion for oversized identity diagnostic
* fix(agents): attach caught error as cause in oversized identity diagnostic
* fix(agents): preserve symlinked identity files
* fix(agents): classify identity size errors exactly
Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>
* fix(agents): preserve supported identity avatars
Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>
* fix(agents): keep identity limit private
Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
(cherry picked from commit 80f6acc8def890c5f54c919d93dc5d79cadf09ea)
* fix(config): bound state-directory .env file reads with size limit (#109487)
* fix(config): bound state-directory .env file reads with size limit
Replace unbounded fs.readFileSync with readRegularFileSync capped at
1 MiB (MAX_STATE_DIR_DOTENV_BYTES) so an oversized .env file is
rejected before loading the entire file into memory.
Resolve symlinks via fs.realpathSync before the bounded read so
symlinked .env files keep working — matching the marketplace.ts
pattern for bounded manifest reads.
* fix(config): add diagnostic when oversized state .env is skipped
Log a warning when the state-directory .env file exceeds the 1 MiB
limit so operators know a configured file was skipped — matching the
pattern from #108200 (plugin catalog bounded read diagnostic).
* fix(config): bound global runtime dotenv file reads with size limit
Replace unbounded fs.readFileSync in readDotEnvFile with readRegularFileSync
capped at 1 MiB so CLI/Gateway startup dotenv loading also gets the bounded
read protection — not just the state-dir service-env path.
This addresses the P1 review finding that the original fix only capped the
helper-level reader while the shared readDotEnvFile used by
loadGlobalRuntimeDotEnvFiles was still unbounded.
(cherry picked from commit 0c221d2b4f7e1f310feb497c9c24cddfae48c181)
* fix(nostr): profile imports no longer crash on invalid fields (#110684)
* fix(nostr): profile imports no longer crash on invalid fields
* test(nostr): define invalid profile import policy
* test(nostr): cover invalid imported URL types
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 9fe92cf5ce918799ffa771e272faaae551b29b26)
* fix(tlon): preserve shutdown when body cancellation fails (#111106)
* fix(tlon): observe shutdown body cancellation failures
* test(tlon): streamline shutdown cleanup proof
* test(tlon): narrow shutdown fixtures
---------
Co-authored-by: ZengWen-DT <290981215+ZengWen-DT@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 5bb969f7de6cb07747e746e90d6444bb935dcb8e)
* fix(qqbot): cancel non-OK direct-upload response body before throwing (#110008)
(cherry picked from commit 17643f385085d68d104d216eae1a08785da4b3ec)
* fix(tui): prevent memory growth during repeated selector searches (#109451)
* fix(tui): bound searchable select regex cache
* fix(tui): discard stale selector regexes
Co-authored-by: wahaha1223 <0668001153@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 80c16ecc8097793166e4c8418b6090fc09e3a90a)
* fix(tlon): bound Urbit auth response body drain to prevent OOM (#109697)
* fix(tlon): bound Urbit auth response body drain to prevent OOM
Replace the unbounded response.text() body drain (discarded after reading
to finalize set-cookie headers) with a streaming reader capped at 64 KiB.
When no body stream is available, fall back to text() for compatibility.
A hostile or misconfigured Urbit endpoint could previously stream an
arbitrarily large body into memory during login.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(tlon): add curly braces to drain loop for lint compliance
* fix(tlon): remove unbounded text() fallback, cancel reader in finally
Remove the unbounded response.text() body-less fallback path. When no body
stream is available, there is nothing to drain — cookie headers are already
finalised. Move reader.cancel() into a finally block so the reader is
released even when read() throws.
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
(cherry picked from commit 4e9b1f4775b0724cc7f28cfe6db79baec8f7fa62)
* fix(tlon): cancel failed auth response bodies (#112059)
(cherry picked from commit e024aa38b9f706f910cc8235a9e8e7aaea9c2336)
* fix(memory-core): guard invalid timestamps in dreaming rankings (#110537)
(cherry picked from commit 1e4e588142fdb1bea797363c38621f293406d0aa)
* fix(security): restore filesystem API after bounded manifest read
Source: 95d632e644b3c826ca74b76494857f9e9a0fd4e8
Target adaptation: this release line does not yet have the skill-file audit path, so only restore the fs/promises import still required by its other deep audit helpers after d5b0218b7ec removed it.
* test(proxy-capture): adapt bounded capture coverage to release test harness
Source: 7cde0ac8c0a821e3641a3418bddad41dda6c4c7b
Target adaptation: import vi explicitly and model Buffer payload persistence so the null-body assertion exercises the shipped store contract.
* style: format backported provider response bounds
* fix: correct release-line backport adaptations
Retain the existing Synology client export and remove source-context imports/constants that have no caller on the .34 release line.
* fix(retry): support abortable operation backoff
Target adaptation for source 40acbb05c9d7cf6783bb4cf4a99f332ef14cde0a: the .34 retry utility predates the per-operation sleeper hook required by Discord's abortable 429 backoff.
* fix(clickclack): cap inbound WebSocket frames
Target adaptation for source 3eec404aab29e9dd78d2e69c9b4e2985f6a326fe: retain the source's 16 MiB ws cap alongside the handshake deadline; this release line predates its shared inbound JSON limit constant.
* fix(openai): bound blank streamed batch records
Target hardening for source ce4a259485f25e238929ba1cc0c17ffbdd393554: count blank JSONL records so newline-only responses cannot bypass the existing output record cap.
* fix(openai): complete blank batch record backport
* fix(browser): run mutation guard before JSON parsing (#104677)
* fix(browser): run mutation guard before JSON parsing
* test(browser): cover auth in mutation guard ordering
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 85a8f4ba8d9fe0fe9eec40173da28d4f59d51d01)
(cherry picked from commit 36ef64341bf8355c3832e56b8fb7ece3b4a0c26f)
* fix(tts-local-cli): handle stdout/stderr stream errors in speech provider (#102347)
* fix(tts-local-cli): handle stdout/stderr stream errors in speech provider
CLI TTS speech provider spawns a child process to generate audio and
registers stdout/stderr data listeners but omits stream error handlers.
stdout carries synthesized audio data. A pipe error mid-generation must
reject the promise so the caller does not silently receive truncated
audio when the child later exits zero. stderr carries diagnostic logs
only — errors there are benign and should not crash the provider.
Apply separate strategies matching vincentkoc's requirement:
- stdout (audio): error → reject(Promise) — surface the failure
- stderr (diagnostic): error → ignore — does not affect audio output
* fix lint: remove unused signal param from mock kill()
* fix(tts-local-cli): contain child stream failures
Co-authored-by: 赵旺0668001248 <zhao.wang1@xydigit.com>
* chore(tts-local-cli): keep release notes in PR body
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 9fa913740d41bb6fdb546514202d52bfd7806e79)
(cherry picked from commit 66099c79c0e1d82b424c63af60d3060c08787db1)
* fix(tts-local-cli): preserve file output on stream errors
Co-authored-by: 赵旺0668001248 <zhao.wang1@xydigit.com>
(cherry picked from commit 45d15aabf9e9b2ab89d33aeca3c650de984cd4d9)
(cherry picked from commit 0d836bb58024cae18b7fc46df40806950e27e63b)
* fix(azure-speech): add timeout to voices list request (#102984)
* fix(azure-speech): add timeout to voices list request
* test(azure-speech): simplify voice timeout proof
* test(azure-speech): mark voice keys as placeholders
---------
Co-authored-by: chengzhichao-xydt <chengzhichao-xydt@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 1ed04910e2de695905431a64cb55f383252b9f8c)
(cherry picked from commit fa440cf51c95ad2ef4608f38c846e4c425f0ceee)
* fix(minimax): add timeouts to OAuth HTTP requests (#102862)
* fix(minimax): add timeouts to OAuth HTTP requests
* fix(minimax): remove duplicate OAuth abort signals
* refactor(minimax): keep OAuth timeout internal
* test(minimax): make OAuth timeout proof deterministic
---------
Co-authored-by: llagy009 <0668001470@xydigit.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 8f8aad9ae69253ecf91526a48f97dcb8d2d43acf)
(cherry picked from commit 3cc03752fd349668c418580389afcc0caaababca)
* fix(google-meet): handle stdout/stderr stream errors in local audio bridge (#101596)
* fix(google-meet): handle stdout/stderr stream errors in local audio bridge
* test(google-meet): prove command bridge stream errors
(cherry picked from commit 5fd5bf2aee1b803e95a8c985b90f117ced7a21e9)
(cherry picked from commit e61d2f9d37044d463e22691ee87bc5cb39bdfbf0)
* fix(google-meet): bound Calendar event lookups (#102157)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 28bbbe4f603c17ca770399f044bd8f25c2c8685f)
(cherry picked from commit fe03932992ab65ca9d7d0f598aa31c0c8679e49c)
* fix(matrix): handle stdout/stderr stream errors in dependency commands (#101597)
* fix(matrix): handle stdout/stderr stream errors in dependency commands
* fix(matrix): type stream-error test process kill
* fix(matrix): harden dependency stream errors
* test(matrix): fix dependency stream test typings
(cherry picked from commit 35d5ea069ae90d9377df69dbdb5c636c05f58ecd)
(cherry picked from commit 141a2e76420dd593b2f3efdd7c9cb8aac2a89ef5)
* fix(matrix): handle event decryption errors during sync (#94416)
Co-authored-by: mushuiyu886 <mushuiyu886@users.noreply.github.com>
(cherry picked from commit 4200745a983534896ef30133af6e23aa00ae59b8)
(cherry picked from commit 663134e30c8b265f89ffd692f6f10f795c2b3735)
* fix(zalouser): clear probe timeout after auth resolves (#101649)
(cherry picked from commit ca8f6e1efd62ea98d4fa496a3e3663ed2d6eba52)
(cherry picked from commit b66d2abccd5ffe0a75f04bf8e51cdb99d89c4456)
* fix(msteams): lowercase content type so attachment classification is case-insensitive (#102431)
* fix(msteams): lowercase content type so attachment classification is case-insensitive
normalizeContentType only trimmed its input. MIME types are case-insensitive
(RFC 2045), and MS Teams relay payloads (SharePoint, OneDrive, Bot Framework CDN)
routinely emit mixed-case values such as "Image/PNG" or
"Application/Vnd.Microsoft.Teams.File.Download.Info". Every downstream
comparison in the attachments module assumes a lowercased value
(startsWith("image/"), === "application/vnd.microsoft.teams.file.download.info",
startsWith("text/html")), so a mixed-case attachment was silently misclassified:
images became documents, HTML bodies were skipped, and file-download candidates
were not resolved.
Lowercase in normalizeContentType so all six call sites match. The sibling
inferPlaceholder in the same file already lowercases via
normalizeLowercaseStringOrEmpty, so this aligns the two paths.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(msteams): route HTML text extraction through normalizeContentType
extractTextFromHtmlAttachments guarded its loop with an exact
`attachment.contentType !== "text/html"` check, which is the same
case-sensitivity gap the rest of the PR closes via normalizeContentType.
A mixed-case "TEXT/HTML" attachment (common from Teams relays; MIME types are
case-insensitive per RFC 2045) was skipped, so a message whose only body text
lived in such an HTML attachment entered the agent path with empty text.
Route the guard through normalizeContentType so mixed-case HTML attachments
reach the body extractor. Export the function and add regression coverage for
mixed-case / whitespace-padded / object-content / non-HTML cases.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(msteams): preserve MIME parameter case
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit e6a2136c3a0b12f124fb3327518244a79d872818)
(cherry picked from commit bdaf9d91415815ec870236bd1261f5ad44759e10)
* fix(msteams): bound team group lookup cache (#102814)
Co-authored-by: sunlit-deng <yang.jiajun1@xydigit.com>
(cherry picked from commit f6b99012435391f18b701330c7b6f40248e6b61c)
(cherry picked from commit 1af683390d2502256eea35d157ea62015d8d2f28)
* fix(tlon): cap SSE payload JSON.parse at 16 MiB to prevent OOM (#101274)
* fix(tlon): cap SSE payload JSON.parse at 16 MiB to prevent OOM
* fix(tlon): cap SSE stream buffer and JSON.parse at 16 MiB to prevent OOM
* chore(tlon): add production-style SSE bounded proof script (#101274)
Adds extensions/tlon/proof-sse-bounded.mts which drives the real
UrbitSSEClient.processStream and processEvent against Node Readable streams
(not unit-test mocks) to demonstrate:
- normal SSE events are still delivered through the stream path;
- an unterminated stream that would grow beyond 16 MiB is rejected before
unbounded accumulation;
- a single SSE payload above 16 MiB is rejected before JSON.parse.
The script passes on this branch and fails 2/3 assertions when run against
origin/main's sse-client.ts, providing the before/after proof ClawSweeper
requested.
* chore(tlon): fix oxlint catch type in proof script (#101274)
* fix(tlon): reject oversized SSE chunk before buffer concatenation
Move the stream byte-limit check before buffer += chunkStr so a
single oversized chunk never lands in the pending buffer. The old
guard ran after concatenation, which still allowed the memory spike
this hardening is meant to prevent.
Add a single-oversized-chunk test to prove the guard fires before
the chunk is concatenated into the pending buffer.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(tlon): remove PR-specific SSE bounded proof script
The proof script was review-only validation for #101274. Durable behavior
coverage lives in sse-client.test.ts (stream buffer bounding, oversized
chunk rejection before concatenation, 16 MiB boundary, normal delivery,
1000 small events). Per ClawSweeper P3 finding, drop the one-off script
from the plugin tree.
* fix(tlon): bound SSE event buffering safely
* test(tlon): avoid unsafe optional chaining
* fix(tlon): count split Unicode at SSE limit
* fix(tlon): parse split SSE delimiters at limit
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 1710ccad2977f39d36e8c6a9aaa908bcd0ad785b)
(cherry picked from commit 938ba5d7fa21057b5be935b8a38a69b4ea0882cf)
* fix(inworld): add timeout to voices list request (#102965)
* fix(inworld): add timeout to voices list request
* refactor(inworld): reuse guarded timeout test helpers
* test(inworld): rely on harness timeout
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit a11449211a2c18b32c14173ff35f1eae7f714e03)
(cherry picked from commit 42e1ab25c9dab2151440d0afb2d985a365086e70)
* fix(voice-call): add timeout to guardedJsonApiRequest (#102884)
* fix(voice-call): add timeout to guardedJsonApiRequest
* fix(voice-call): bound provider JSON requests
---------
Co-authored-by: chengzhichao-xydt <chengzhichao-xydt@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 5b916cb319f84cd3cda88f87bf0f2fff5231c7ba)
(cherry picked from commit 2de4b2d0708c46e451ca90bdcfeda329f9a3a318)
* fix(file-transfer): reject oversized inline file writes before node dispatch (#104556)
* fix(file-transfer): cap inline file write payloads
* fix(file-transfer): validate inline base64 before decoding
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit fdf581281746ecc28be6c58d608569313a9e31aa)
(cherry picked from commit 7fc1041e2737d43c38d18a7313678db774333e2d)
* fix(imessage): apply authoritative projection in anchorless recovery (#104218)
* fix(imessage): apply authoritative projection in anchorless recovery
Rebuild on latest main with imessage-only changes: authoritative history
projection (optional destination_caller_id), whole-path inbound proof tests,
and no unrelated restart.ts diff.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(imessage): restore recovery cursor API and format tests
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(imessage): add monitor whole-path L3 proof for #104136 recovery
Exercise issue synthetic payloads through monitorIMessageProvider for
authoritative remote reply routing and from-me suppression before dispatch.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(imessage): clear stale destination_caller_id when history omits it
Exact-GUID history is authoritative for destination_caller_id. When the
history row omits that outgoing-only field, clear any stale notification
value instead of inheriting it into the recovered inbound projection.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: sm <sm@zwdeMacBook-Pro.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 6ef3e87583eda04fc3c790b68af86e021e68733c)
(cherry picked from commit 184deb936f55f8137d0842067893f4fe7d57e18d)
* fix(imessage): narrow recovered projection before use (#106022)
(cherry picked from commit 8a2da4b1bf1555fe0bfaf705eb57300c673c81be)
(cherry picked from commit fa55df678fffa3cd716eb29e71be2cd516c54b96)
* fix(twitch): strip internal tool-trace banners from outbound text (#103109)
* fix(twitch): strip internal tool-trace banners from outbound text
Co-authored-by: Masato Hoshino <246810661+masatohoshino@users.noreply.github.com>
* fix(twitch): strip internal tool-trace banners from outbound text
---------
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: Masato Hoshino <246810661+masatohoshino@users.noreply.github.com>
(cherry picked from commit 90b68536c441a301ea8be08d53beb3486b50566b)
(cherry picked from commit afbd2caff18677c15564b51cce0a6b57d0ae6804)
* fix(synology-chat): strip internal tool-trace banners from outbound text (#102925)
* fix(synology-chat): strip internal tool-trace banners from outbound text
* fix(synology-chat): satisfy eslint curly rule
* fix(synology-chat): add sanitizeText to outbound type contract
* fix(synology-chat): use canonical outbound sanitizer type
---------
Co-authored-by: Pick-cat <266665499+Pick-cat@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 7eb163d90582895150403fa320635a3ef85c81bd)
(cherry picked from commit bdc4440e2f48147a6dca84ae5a4a275a8aa7cdbe)
* fix(tlon): strip internal tool-trace banners from outbound text (#103450)
Route assistant-visible Tlon output through the shared sanitizer and prove the rendered Urbit poke payload for DMs, groups, and media captions.
Co-authored-by: masatohoshino <g515hoshino@gmail.com>
(cherry picked from commit 1d205424494de6633857796ff56a3cc09f41552b)
(cherry picked from commit b8b5e9d72b30aadedfd591067d8918ccde6ef951)
* fix(nextcloud-talk): strip internal tool-trace banners from outbound text (#101712)
* fix(nextcloud-talk): strip internal tool-trace banners from outbound text
* fix(nextcloud-talk): sanitize inbound replies
Co-authored-by: liyuanbin <li.yuanbin1@xydigit.com>
* test(nextcloud-talk): prove low-level send text preservation
* test(nextcloud-talk): focus inbound sanitizer coverage
* fix(nextcloud-talk): report stripped replies as non-visible
* docs(changelog): note Nextcloud Talk reply sanitization
* chore: keep PR changelog-neutral
---------
Co-authored-by: Pick-cat <266665499+Pick-cat@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: liyuanbin <li.yuanbin1@xydigit.com>
(cherry picked from commit 8a93d288e2f57db13251e7d3f059e72a411b228a)
(cherry picked from commit 3f1774653aefa225eea770b0491008a83e6a142c)
* fix(microsoft-foundry): reject malformed endpoints (#104796)
(cherry picked from commit f5a50db5691b828d830bd33b6ac11a0a99f50c05)
(cherry picked from commit 1bc1ec21b49ee1a1350ad5688fd2420f270acfb9)
* fix(google): bound realtime browser token requests (#106034)
* fix(google): bound realtime browser token requests
* fix(google): satisfy realtime timeout checks
* test(google): use placeholder browser key
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit d33254b72efc4a46824f218c9a43ff830804c96f)
(cherry picked from commit ac8e45955d567dd78e5cf0e02599cb58e008da07)
* fix(github-copilot): bound device flow requests (#103255)
* fix(github-copilot): bound device flow requests
* docs(changelog): note Copilot login timeout
* fix(github-copilot): bound device flow requests
* fix(github-copilot): bound device flow requests
* fix(github-copilot): bound device flow requests
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
(cherry picked from commit 1e3dea75d5690e36f135c39eb4f792815b87c19d)
(cherry picked from commit faa4cf7321ce62b48a5f2c03f198e1691030acf0)
* fix(openai): add timeout to realtime client-secret requests (#102860)
* fix(openai): add timeout to realtime client-secret requests
* test(openai): prove realtime timeout through real guard
* test(openai): route realtime timeout proof through guard
* fix(openai): bound realtime client-secret requests
Co-authored-by: llagy009 <0668001470@xydigit.com>
* fix(openai): align realtime secret timeout
---------
Co-authored-by: llagy009 <0668001470@xydigit.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 1836275810cb9cb3f7487cf66a8f7c2f0b16d853)
(cherry picked from commit f2e18c4250592d8dcfc8a7bad17531fb83c3db63)
* fix(memory-core): guard supplement lookup in resolveMemoryReadFailureResult with try-catch (fixes #101809) (#101902)
* fix(memory-core): guard supplement lookup in resolveMemoryReadFailureResult with try-catch (fixes #101809)
* fix(memory-core): preserve primary read errors
---------
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
(cherry picked from commit 1aee742d230e5e50f6f580e19655fa22b21eefee)
(cherry picked from commit 7427f3ef171139edb693dec56aec6141222d293d)
* fix(browser): guard act hooks on current tab URL (#104095)
* fix(browser): guard act hooks on current tab URL
* test(browser): align navigation policy hook mock
* test(browser): exercise real hook navigation guard
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 4bf4cacb37a9c45be03dac105d86352a0e9a0a8f)
(cherry picked from commit 72e4a8b21cee6cb848e50b6a211f1380bd293c6c)
* fix(google-meet): bound Google API requests (#102149)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 51b4e78c339de48614f5fc578e1d4685c2ca9d8b)
(cherry picked from commit 2bc883a7a23812ca9a610ae6c75119b63100fcf7)
* fix(browser): reject non-page json new targets (#104129)
* fix(browser): reject non-page json new targets
* fix(browser): adopt only validated raw CDP targets
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 7027d2c227281d814266311bebab7581b899d6dc)
(cherry picked from commit 7dea1a3cd7ac5643ec9e5c32f19fc041c5a7fc55)
* fix(agents): skip wham probe when oauth access token is locally expired
(cherry picked from commit e975d49238083091b265748cd6ffb54dc8f022bd)
(cherry picked from commit f5b234db3fc58b4275f4e6b0e65393f3631da659)
* fix(media): accept matching repeated content lengths (#102939)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 3f68e1b5e3a7a4a66660722ac8fd10c256a63b40)
(cherry picked from commit 7693544cccc64ac359597555185fdc8f530556d0)
* fix: 429 errors without rate-limit wording skip the same-model retry (#99097)
* fix: 429 errors without rate-limit wording skip the same-model retry
Aggregated providers such as OpenRouter provider pools surface transient
upstream throttles as a bare "429 <generic text>" with no RPM/TPM wording
and no Retry-After header. resolveShortWindowRateLimitRetry required one
of those hints, so these errors bypassed the same-model retry ladder and
failed the turn on the first attempt.
Treat a status-prefixed 429 as short-window once the long-window guard
(quota, usage, billing wording) has filtered its phrasings, and let the
existing backoff ladder pace the retry.
* test(agents): streamline bare 429 coverage
---------
Co-authored-by: Altay <altay@hey.com>
(cherry picked from commit 9330ad86ffdaae640ff778572028644afe29d92a)
(cherry picked from commit f6db641108cd139f211cabeb6834f57916a4f2bf)
* fix(sdk): add prototype-pollution guard to migration config merge (#103059) (#106116)
* fix(sdk): add prototype-pollution guard to migration config merge
mergeMigrationConfigValue and writeMigrationConfigPath had no
isBlockedObjectKey guard, allowing __proto__/constructor/prototype
keys from imported config files to trigger prototype pollution.
Add the same guard used by the sibling config-path writer
(setConfigValueAtPath/parseConfigPath) to reject blocked object
keys before they reach a bracket assignment.
Fixes #103059
* fix(sdk): harden migration config patches
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit b6330edbe4bfd08167a13ff0862a3fcb42ba79d3)
(cherry picked from commit 4fe0cf4ddb1686fe0e824536d281fb4295150468)
* fix(session): swallow onRecordError throw to avoid unhandled rejection (#106951)
* fix(session): swall…
Makes #102992 merge-ready for the ClawSweeper automerge loop.
The edit pass should inspect the live PR diff, review comments, and failing checks; rebase if needed; keep the contributor branch credited; and stop only when validation is green or an external blocker is proven.
Known failing checks:
Source
Replacement for #102992 because the source branch could not be updated.
Original contributor: @masatohoshino.