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.
Fixes Copilot image understanding by exchanging OAuth tokens for Copilot API tokens, routing Copilot Gemini image requests through Chat Completions, and sending the prompt in user content with Copilot vision headers.
Real behavior proof:
- Old Responses route with real Copilot key reproduced `400 model gemini-3.1-pro-preview does not support Responses API`.
- Fixed route with the same real Copilot key returned `Cat`.
- Final CLI live smoke returned `ok: true` and `text: Cat` for `github-copilot/gemini-3.1-pro-preview`.
Verification:
- pnpm test src/media-understanding/image.test.ts extensions/github-copilot/models.test.ts extensions/github-copilot/stream.test.ts src/agents/pi-hooks/compaction-safeguard.test.ts -- --reporter=verbose
- pnpm check:changed via Blacksmith Testbox tbx_01krgt56pqmft8txekt017wke6, Actions run https://github.com/openclaw/openclaw/actions/runs/25803926150, exit 0.
Refs #80393, #80442.
Co-authored-by: Yang Haoyu <150496764+afunnyhy@users.noreply.github.com>