mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 14:57:42 +00:00
|
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions
Sync Helm Chart Tags / Ignore non-main push (push) Waiting to run
Sync Helm Chart Tags / Sync chart tags (push) Waiting to run
* 🖼️ feat: Return Sandbox Images From `read_file` as Viewable Artifacts The code-execution sandbox `read_file` path refused every image extension because it reads files via `cat` over codeapi's JSON `/exec` transport, which lossily corrupts non-UTF-8 bytes. The skill-file read path already surfaced images as artifacts; this brings the sandbox path to parity so an agent can actually see a chart/screenshot it reads. - `readSandboxImage` (process.js): a Python base64 reader over `/exec` with an in-sandbox size guard so oversize images never cross the wire; base64 is ASCII-safe where `cat` corrupts. - `handleSandboxImageRead` (handlers.ts): byte-integrity check (guards against a truncated `/exec` stdout), MIME resolved purely from the magic-byte sniff (extension only routes; a mislabeled non-image falls back to the bash hint), and graceful degradation on every failure mode. - Shared `buildImageArtifactResult` used by both read paths; the result's `artifact.content` image_url reaches the UI (tool-end callbacks save it as an attachment) and the LLM (SDK folds it into the model-visible message for Anthropic/OpenAI/Google). * ✅ test: Sync read_file code-only description assertions with image wording * 🛡️ fix: Harden sandbox image reads (regular-file guard, completeness check) Addresses Codex review on PR #14277: - readSandboxImage now os.stat's the target and rejects non-regular files (FIFOs, sockets, /dev/* symlinks) via stat.S_ISREG, and bounds the read at limit+1 bytes — a device/FIFO can no longer stream unbounded into memory until the request times out. - handleSandboxImageRead validates completeness (not just the magic header): PNG must end with the IEND trailer and WebP's RIFF size must match the byte length, so a truncated/interrupted image degrades to the bash hint instead of being sent as a corrupt image_url. JPEG/GIF stay header-level (they can carry trailing metadata; a strict end-marker would risk false rejections). * 🩹 fix: Chunk sandbox image reads to fit the runner stdout cap Inlining any real image failed with "is an image file (.png) and cannot be read as text". Root cause: readSandboxImage base64-encodes the file to STDOUT, but the runner caps stdout at SANDBOX_OUTPUT_MAX_SIZE (1024 bytes by default) and SIGKILLs the job on overflow (status OL), truncating the JSON mid-base64. The parse then threw and the handler degraded to the binary hint. The in-sandbox MAX_BINARY_BYTES=5MB guard never fired because the *transport*, not the file size, is the real ceiling: a 5MB image needs ~6.8MB of stdout. Reproduced against a live MicroVM — a 186KB matplotlib PNG died with 'stdout length exceeded' at exactly the 65536-byte cap. Read the file in windows instead: each /exec pulls raw bytes at an offset and base64s only that slice, so every response stays under the cap regardless of how the runner is configured; the chunks are reassembled and verified against the sandbox-reported total. Verified end-to-end on a real MicroVM: 25KB and 186KB PNGs both round-trip byte-exact (sha256 match). Also: - Detect the truncation explicitly (status OL) and name the fixable cause (chunk size / SANDBOX_OUTPUT_MAX_SIZE) instead of "unexpected output". - Parse the LAST stdout line so a shell banner can't break the read, and include a stdout snippet when it genuinely is unparseable. - LIBRECHAT_CODE_IMAGE_CHUNK_BYTES (default 32KB) tunes the window. - Tests drive the real reader against a mocked /exec transport rather than mocking readSandboxImage, which is why the existing suite stayed green through this bug. * 🎯 fix: Cap sandbox inline images at 1MB, separate from skill-file reads The sandbox and skill-file image paths shared MAX_BINARY_BYTES (5MB), but their transports differ: skill files stream from storage, while sandbox bytes come back base64 over /exec stdout under the runner's output cap, so the reader windows the file and cost scales in round-trips (~160 at 5MB vs ~32 at 1MB). Nothing is gained by allowing more — vision providers downsample to ~1.5-2k px regardless, so multi-MB originals buy no fidelity while grinding through round-trips. Give the sandbox path its own MAX_SANDBOX_INLINE_IMAGE_BYTES (1MB), used for both the read cap and the over-limit message (which previously quoted 5MB while the reader enforced something else). Skill-file reads keep 5MB. Verified against a live MicroVM: a 186KB PNG round-trips byte-exact, and a 1.4MB file returns tooLarge in a single round-trip with zero bytes transferred, degrading to the existing bash_tool hint. |
||
|---|---|---|
| .. | ||
| controllers | ||
| middleware | ||
| routes | ||
| services | ||
| utils | ||
| cleanup.js | ||
| experimental.js | ||
| index.js | ||
| index.metrics.spec.js | ||
| index.spec.js | ||
| socialLogins.js | ||
| socialLogins.spec.js | ||
| telemetry.js | ||
| telemetry.spec.js | ||