Two issues flagged by Greptile:
1. CSV/Markdown exception was dead code.
file-type v22 returns undefined (not "text/plain") for plain-text buffers
that have no binary magic bytes. The guard `sniffedMime === "text/plain"`
was therefore always false, so the early-return never fired and CSV uploads
continued to be rejected.
Fix: check `!sniffedMime` (no binary signature) and add a null-byte scan
of the first 8 KiB to rule out binary data that happens to have no known
magic bytes. Pass buffer into assertHostReadMediaAllowed to enable this.
2. "rejects binary disguised as CSV" test used PNG bytes.
assertHostReadMediaAllowed allows all image kinds unconditionally
(sniffedKind === "image" → early return), so the promise resolved instead
of rejecting. The test would have failed with "Received promise resolved".
Fix: use ZIP magic bytes (PK\x03\x04). file-type detects application/zip,
which is not image/audio/video, so it falls through to the final throw.
Extend the text/plain sniff exception to cover text/markdown in addition
to text/csv. Both formats are structurally indistinguishable from plain
text at the byte level, so the same pattern applies.
CSV files (text/csv) were rejected by assertHostReadMediaAllowed because
content sniffers report text/plain for CSV — CSV is structurally
indistinguishable from plain text at the byte level.
Fix:
- Add text/csv to HOST_READ_ALLOWED_DOCUMENT_MIMES
- Add a targeted exception: when sniffed MIME is text/plain AND the
extension-derived MIME is text/csv, allow the upload. The text/plain
sniff already confirms the content is valid UTF-8 text (not binary),
so the .csv extension is sufficient to confirm operator intent.
Binary data disguised as .csv is still rejected because its sniffed MIME
will not be text/plain (e.g. a PNG file sniffs as image/png).
Fixes#63604
* fix(cron): preserve all fields in announce delivery by removing summarization instruction
The delivery instruction appended to the cron agent prompt contained the word
'summary', causing LLMs to condense structured output non-deterministically and
drop fields on delivery. Replace with 'response' and add explicit instruction
to reproduce all fields exactly.
Fixes#58535
* chore(changelog): add cron announce entry
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* feat(memory-lancedb): add cloud storage support to memory-lancedb
- Pass storageOptions to LanceDB connection
# Conflicts:
# extensions/memory-lancedb/index.ts
# Conflicts:
# extensions/memory-lancedb/config.ts
* support env var
* make storageOptions sensitive
* feat(gateway,ui): add Model Auth status card to Overview
Adds a new `models.authStatus` gateway endpoint that combines
`buildAuthHealthSummary()` (token expiry/status) with
`loadProviderUsageSummary()` (rate limits) into a single response
suitable for UI rendering. Strips credentials - only ships status,
expiry, remaining time, and rate-limit windows.
Adds a corresponding "Model Auth" card to the Overview dashboard
showing provider token status and rate limits at a glance. Attention
items are raised when OAuth tokens are expiring or expired.
Also catches the OAuth token sink class of bug: if multiple profiles
exist per provider/account and tokens are drifting out of sync, this
surfaces it immediately in the dashboard instead of silently falling
back to a different provider.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* CHANGELOG: note Model Auth status card on Overview
* UI/Overview: render Model Auth card during load with N/A placeholder
* models.authStatus: env-backed OAuth escape hatch + expectsOAuth missing signal
---------
Co-authored-by: Lobster <10343873+omarshahine@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(channels): resolve bundled channel catalog from dist/extensions/ in published installs
* refactor(channels): delegate bundled channel catalog loader to resolveBundledPluginsDir
---------
Co-authored-by: Claude <noreply@anthropic.com>