mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-11-01 03:26:18 +00:00
* 🖼️ fix: Stop Reporting a Failed Sandbox Image Read as an Unreadable Format `read_file` on a `/mnt/data` image collapsed every failure — rate limit, missing path, truncated transfer, transport error — into the binary-file hint, whose image branch reads as a permanent capability limit ("is an image file and cannot be read as text"). The model stopped retrying, and the operator had no way to tell which failure had actually occurred. The failure that surfaced it: the reader windows the bytes through `/exec` stdout, one call per window, against the Code API's per-user execution limiter (20 requests / 30s in the reference deployment). At a fixed 32KB window a 122KB chart cost 4 calls and a 1MB image cost 33 — more than a whole limiter window, so anything over ~640KB could never complete. A turn that generates several charts and reads them back exhausts the budget partway through and reports the 429s as unreadable images. - `handlers.ts`: failed reads name the real cause and the affordance that matches it — rate-limited waits and retries, a missing path lists the directory, a truncated transfer retries. The "cannot be read as text" phrasing is now reserved for bytes that are not a supported image. An image past the inline budget says to downscale and read the smaller copy rather than pointing at `bash_tool`, which cannot show an image. - `process.js`: the window is derived from the runner's stdout budget (48,960B vs 32,768B, so a 122KB chart is 3 calls and 1MB is 22), halves and re-reads the same offset when a runner truncates anyway (remembered per Code API, with the env remedy logged), waits out a rate limit it can afford instead of discarding the bytes already pulled, and stops at a 24-call ceiling so no read stalls a turn across limiter windows. - `utils/code.ts`: shared `getCodeApiRetryAfterMs` (header, then the `retry_after_seconds` body); `skillFiles.ts` drops its private copy. * ♻️ refactor: Move the Sandbox Image Reader Into TypeScript Addresses the review round on #15453. - P1: windowing, window sizing, the in-sandbox reader script, response parsing and byte assembly move to `packages/api/src/files/code/image.ts`, and the Code API rate-limit policy to `packages/api/src/utils/code.ts`. `process.js` keeps only the `/exec` transport it owns. Both new modules are tested against their real implementations (19 + 13 cases), including the round-trip ceiling, the changed-file guard and the shell-injection guard on the reader script. - P2: a configured stdout budget below the old 8KB window floor produced a window the runner could never emit, and narrowing was pinned to the same floor, so no retry could succeed. The window now aligns to the base64 group size instead, and the round-trip ceiling bounds what a small budget costs. - P2: `.env.example` documented a 32,768-byte default that no longer holds and never mentioned the stdout budget. It now describes `LIBRECHAT_CODE_SANDBOX_OUTPUT_MAX_SIZE` as the setting to tune, with the chunk override as the escape hatch. - P3: `process.spec.js` no longer reimplements the retry parser in its module mock. Behaviour is tested where it lives; the mock is a declared passthrough and the spec covers what the transport still owns — session forwarding, the profile header, parser hand-off and error logging. - P3: `getCodeApiRetryAfterMs` reads the response body through `in` narrowing rather than an `as` assertion. - P3: the window-sizing JSDoc no longer claims a multiple of 3 in the one case that is not — an explicit `LIBRECHAT_CODE_IMAGE_CHUNK_BYTES`. * 🎯 fix: Size Sandbox Image Reads to What the Limiter Can Deliver Addresses review round 2 on #15453. - Narrowing now halves the caller's own failing window instead of the shared learned value, and the learned value only moves down to the narrowest size any read needed. Reads run concurrently (one per tool call), so two reads failing at the same size were compounding into a window two steps smaller than the runner would have accepted, and persisting it for every later read. - Narrowing continues until a runner accepts a window or a floor below which no runner could serve an image at all. Two halvings stopped at 12,240 bytes — still ~16KB of base64 — so an 8-10KB stdout cap that was not configured up front stayed unreachable. - The round-trip ceiling is now one limiter window (20), and a read that cannot finish within it says so from the FIRST response rather than spending the whole budget rediscovering it: the first window reveals both the file size and what a call really delivers. A near-limit image no longer drains the turn's executions before failing, which is what made the wait budget look too small. - The round-trip message names the size this deployment can actually inline, so the model has a downscale target instead of a guess. - `python3: not found` from the sandbox reader was matching the generic "not found" in `isSandboxMissingFileError` and being reported as a missing image path, sending the model to `ls /mnt/data` while hiding a runner dependency. Image reads now classify only path-specific ENOENT forms as a missing file. * 📐 fix: Size a Truncated Read's Retry From the Cap It Revealed Addresses review round 3 on #15453. A ~1KB sandbox stdout cap is a real runner default, and the 1,536-byte narrowing floor sat above it: discovery stopped one step short and declared every image unreadable, even though small ones fit comfortably in the 576-byte window the configured path already derives. Narrowing now runs until no smaller window exists. It also no longer has to grope its way down: a truncated response emitted exactly as much as the runner allows, so its length measures the cap this deployment never declared, and the retry is derived from it directly — one round-trip instead of the eight blind halvings it takes to fall from ~49KB to ~1KB. Blind halving remains the fallback and bounds the result either way, so every retry is strictly smaller than the window that just failed. |
||
|---|---|---|
| .. | ||
| controllers | ||
| middleware | ||
| routes | ||
| services | ||
| utils | ||
| cleanup.js | ||
| csp.spec.js | ||
| experimental.js | ||
| experimental.spec.js | ||
| index.js | ||
| index.metrics.spec.js | ||
| index.spec.js | ||
| socialLogins.js | ||
| socialLogins.spec.js | ||
| telemetry.js | ||
| telemetry.spec.js | ||