Commit Graph

518 Commits

Author SHA1 Message Date
Afonso Coutinho
0051023056 fix: skill test-task / precision helpers crash on a non-dict skill (#1638) 2026-06-03 08:59:24 +09:00
Afonso Coutinho
8783f12c4c fix: builtin_actions heuristics crash on a truthy non-string input (#1639) 2026-06-03 08:59:16 +09:00
Afonso Coutinho
82c09dd768 fix: split_chunks emits a duplicate trailing chunk for text over size-overlap (#1573) 2026-06-03 08:57:54 +09:00
Afonso Coutinho
c3bf32d1b1 fix: monthly schedule label shows 21th/22th/31th (ordinal suffix for days >20) (#1577) 2026-06-03 08:57:47 +09:00
red person
df3864bd15 Normalize session CLI counters (#1578)
* Normalize session CLI counters

* Keep sessions CLI test imports isolated
2026-06-03 08:57:41 +09:00
red person
ffeb7d8c97 Reject invalid preset CLI entries (#1579)
* Reject invalid preset CLI entries

* Use modern preset CLI test loader
2026-06-03 08:57:35 +09:00
red person
a6b7a7bc60 Validate signature CLI PNG data (#1580)
* Validate signature CLI PNG data

* Keep signature CLI test imports isolated
2026-06-03 08:57:28 +09:00
red person
0cc1814658 Reject empty mail CLI recipients (#1581)
* Reject empty mail CLI recipients

* Keep mail CLI test imports isolated
2026-06-03 08:57:23 +09:00
red person
8051e25c65 Reject CalDAV writeback events without uid (#1582) 2026-06-03 08:57:15 +09:00
red person
0ad5cd783b Skip invalid research service sources (#1583) 2026-06-03 08:57:09 +09:00
red person
953305a5af Remove duplicate update database body (#1584) 2026-06-03 08:57:03 +09:00
red person
15a3b71802 Require runnable dispatcher subcommands (#1585)
* Require runnable dispatcher subcommands

* Use modern dispatcher test loader
2026-06-03 08:56:56 +09:00
red person
e68d0448b8 Parse all AMD GPU check args (#1586) 2026-06-03 08:56:48 +09:00
red person
db3a5c17b0 Reject backup output inside data dir (#1587) 2026-06-03 08:38:27 +09:00
red person
f39c87561b Save only string personal doc paths (#1566) 2026-06-03 08:37:29 +09:00
Mahdi Salmanzade
f7df069ca1 fix(ui): stop welcome-screen tip from clipping on narrow phones (#1612)
The empty-state tip ("Add an AI endpoint from Settings...") shares a 60px
max-height ceiling with the one-line .welcome-sub / .welcome-version. On
narrow phones the welcome block shrink-wraps and the tip wraps to 4-5 lines
(~67px), so the shared ceiling clipped its last line ("...key into the
chat.") - the only setup hint a first-run user gets.

Give .welcome-tip its own taller max-height (120px), placed above the
@media (max-height: 650px) block so that rule's max-height:0 still collapses
the tip on short viewports. .welcome-sub / .welcome-version are untouched,
and desktop is unchanged (the tip is ~50px there, well under the ceiling).
2026-06-03 08:37:23 +09:00
.bulat
eacb99f963 docs: clarify host Ollama with Docker (#1594) 2026-06-03 08:37:17 +09:00
Wes Huber
fb1341b629 fix(cookbook): set UTF-8 encoding for detached download/serve subprocesses (#1599)
On Windows, Python defaults to the active code page (cp1252) for
subprocess I/O. HuggingFace CLI outputs U+2713 (✓) when validating
tokens, which cp1252 cannot encode, crashing the download process.

Set PYTHONUTF8=1 and PYTHONIOENCODING=utf-8 in the subprocess
environment so Unicode output from hf/pip/llama-server is handled
correctly.

Fixes #1543

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-03 08:37:11 +09:00
Afonso Coutinho
19b6cbac12 fix: skills CLI summary crashes on a non-string description (#1595) 2026-06-03 08:37:05 +09:00
Afonso Coutinho
258fe455eb fix: research CLI summary crashes on a non-string query (#1596) 2026-06-03 08:36:57 +09:00
Afonso Coutinho
667c663668 fix: gallery CLI image serialization crashes on a non-string prompt (#1598) 2026-06-03 08:36:51 +09:00
Afonso Coutinho
0283216e67 fix: rag_server add/remove_directory crashes on a non-string directory arg (#1614) 2026-06-03 08:36:45 +09:00
Afonso Coutinho
77313170c6 fix: search query helpers crash on a non-string query (#1604) 2026-06-03 08:36:01 +09:00
Afonso Coutinho
0d25dfb5f4 fix: shared MCP truncate() crashes on None/non-string tool output (#1605) 2026-06-03 08:35:54 +09:00
Afonso Coutinho
6df0f5e6df fix: _sanitize_export_filename crashes on a non-string session name (#1607) 2026-06-03 08:35:47 +09:00
Afonso Coutinho
382d49d887 fix: validate_caldav_url crashes with TypeError on a non-string URL (#1608) 2026-06-03 08:35:16 +09:00
Afonso Coutinho
0d88c9989e fix: mcp CLI _serialize crashes when stored env JSON is a list (#1609) 2026-06-03 08:35:09 +09:00
Zarl-prog
5462e36d10 fix(ui): add missing Escape key handlers for email-lib-modal, model-picker-menu, and sort dropdowns (#1487)
CONTEXT: Several interactive elements lacked Escape key handlers: the email library modal was not in dynamicModals, the model-picker popup had no Escape close, and the session/model sort dropdowns only closed on outside click.

CHANGE: Adds email-lib-modal to the dynamicModals array in the Escape handler so it gets dismissed via dismissModal. Adds a check for model-picker-menu.open before the modal chain to close the dropdown on Escape. Adds checks for session-sort-dropdown and model-sort-dropdown display=block before the document panel minimize fallback.

WHY: Users expect consistent Escape-to-close behavior across all modals, overlays, and popups. These four were the only interactive containers in the app that ignored the Escape key entirely.

IMPACT: Pressing Escape now closes the email library modal, model picker popup, session sort dropdown, and model sort dropdown -- matching user expectations and the behavior of every other modal in the app.
2026-06-03 08:14:27 +09:00
Paulo Victor Cordeiro
5b0c7442ee fix: rename local url-quote import to avoid shadowing module-level _q (#1471)
The 'from urllib.parse import quote as _q' at line 734 shadows the
module-level _q (istrstrstrstrstrstrIMAPutility) imported from email_helpers, causing
UnboundLocalError at lines 191 and 278 where _q is used before the
local import executes. This silently breaks the entire auto-summarize
pass.
2026-06-03 08:14:19 +09:00
Paulo Victor Cordeiro
441905bc13 fix: guard AI tidy verdict against non-string LLM output (#1486)
The AI document-tidy endpoint parses verdicts from LLM JSON output
and calls .lower().strip() directly. If the model returns null or a
non-string element, this crashes with AttributeError. Coerce to str
so malformed output is treated as 'keep' instead of crashing.
2026-06-03 08:14:10 +09:00
Paulo Victor Cordeiro
24be3f3ca8 fix: guard uid.decode() in auto-classify warning log against str UIDs (#1472)
Every other uid.decode() call in this function uses
'uid.decode() if isinstance(uid, bytes) else str(uid)' but the
warning at line 832 does bare uid.decode(), crashing with
AttributeError when uid is already a string.
2026-06-03 08:13:01 +09:00
Paulo Victor Cordeiro
cf60a14d74 fix: capture download exit code before test consumes it (#1497)
The shell pattern 'if [ $? -eq 0 ]; ... else ... echo DOWNLOAD_FAILED (exit $?)' always reports 'exit 1' because $? inside the else branch is the exit code of the [ test command, not the download. Capture into _ec first.
2026-06-03 08:12:54 +09:00
Paulo Victor Cordeiro
bd0845e081 fix: guard sp.destroy() in _loadScheduled against null spinner (#1495)
When the scheduled folder is opened with cached data, sp is null
(the loading spinner is skipped). _loadScheduled receives null and
calls sp.destroy() unconditionally, crashing with TypeError.
2026-06-03 08:12:47 +09:00
Paulo Victor Cordeiro
dc3421c34e fix: return sorted model list on first call in group chat (#1484)
Both _getModels() and getAllModels() store the sorted copy in a cache
variable but return the original unsorted array on first invocation.
Subsequent calls return the cache (sorted), causing inconsistent
model picker ordering on first render.
2026-06-03 08:12:37 +09:00
lekt8
1f743970dd Don't lose deep-research findings when synthesis times out (#1551) (#1562)
Two problems made deep research report "No information could be gathered" even
after it had extracted findings, on slow local models (reporter served a 20B
via LM Studio):

- _synthesize hard-capped its LLM call at timeout=60, while extraction uses the
  user's extraction_timeout (300s here) and the final report uses 180s. The slow
  model needed >60s to synthesize the round's findings, so synthesis timed out
  after 3 attempts. Raised it to 180s to match the final-report call.

- When synthesis produced no report (it returns the unchanged, still-empty
  report on failure during round 1), the run hit
  `if not report: return "No information could be gathered…"` and discarded the
  findings it had already gathered. Now it falls back to a compiled report built
  from those findings (_fallback_report) so the user keeps the gathered material.

Tests stub the LLM (no live model/DB), pin the synthesis timeout >= 180, that the
fallback surfaces the findings rather than the give-up message, and that a failed
synthesis preserves the previous report.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 08:11:44 +09:00
Afonso Coutinho
c9361262df fix: APIKeyManager.load crashes app startup on a corrupt/wrong-shape api_keys.json (#1565) 2026-06-03 08:11:37 +09:00
lekt8
0e6cbd8315 Drop GPU-only flags from the CPU-only (-ngl 0) serve command (#1433)
A CPU-only llama.cpp serve config still emitted --flash-attn on and exported
GGML_CUDA_ENABLE_UNIFIED_MEMORY=1 (independent toggles, often left on by an Auto
profile), so the command mixed "zero GPU layers" with CUDA/flash-attn and failed
to start (issue #1291). Gate both on a _cpuOnly check (ngl == 0). GPU serving is
unchanged — the gate only affects the ngl=0 path.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 04:26:15 +09:00
Zeus-Deus
5c6bd0fc2b Fix Edge/Chromium sidebar section-title clipping (#1420)
Sidebar section titles were vertically clipped in Chromium/Edge (fine in
Firefox). Raise line-height 1 → 1.3, mirroring the existing .list-item fix.
The titles are flex-centred in a fixed-height (29px) header, so this adds
glyph headroom without any reflow.
2026-06-03 04:24:29 +09:00
lekt8
57abe69173 Let the output "x" delete work when no model/session exists (#1431)
deleteMessage() bailed at `if (!sessionId) return;`, so the "x" on an output
shown before a model/API was selected did nothing — there's no session yet
(issue #1428). The session id is only needed for the server-side delete; without
one (or with no persisted message ids) we now fall through to removing the DOM,
so the "x" always at least dismisses the bubble.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 04:20:48 +09:00
lekt8
583df3dd6a Recognize gemma3/llama4/mistral-small3.1+/multimodal as vision models (#1430)
is_vision_model() classified several genuinely multimodal families as text-only
because their names contain neither "vision" nor "vl": Gemma 3 (4b+), Llama 4,
Mistral Small 3.1/3.2, and *-multimodal models (e.g. phi-4-multimodal). For those
the attached image was stripped before the request, so the model never saw it —
a "can't read the image" report (issue #1274), common with Ollama tags like
gemma3:4b.

Add those keywords (plus a generic "multimodal"). Per the file's err-toward-True
policy (#124), a rare text-only tag treated as vision is the safer failure than
dropping a real image. Guard tests confirm the text-only siblings (gemma2, plain
gemma, mistral-small, phi-3) are not over-matched.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 04:17:40 +09:00
Isharak
70103d8719 fix(email): no-op IMAP connection leak in _auto_summarize_pass_single on exception (#1423)
`_auto_summarize_pass_single` in `routes/email_pollers.py` opens a
long-lived IMAP connection at line 172 and then performs ~700 lines of
work — IMAP `select`/`FETCH`/`SEARCH`, network POSTs to the LLM
endpoint, SQLite writes, and per-uid awaits. The only `conn.logout()`
calls were on three safe paths (early `"No recent emails"`, early
`"No model configured"`, and the happy path at the very end). If any
exception fired between `conn` being created and the final happy path,
the outer `except` block at line 921 caught it, logged, and returned —
without ever calling `conn.logout()`. The IMAP socket leaked until
the server's idle timeout killed it.

This is the same shape as the just-merged upstream fixes #1325
(`_imap_move` in `routes/email_helpers.py`) and #1330 (`_list_emails_sync`
in `routes/email_routes.py`), but in the *background* poller path —
`_auto_summarize_poller` invokes it every 30 min, so the leak
accumulates on every crashed pass instead of being a transient
request-path leak.

The fix is the exact try/finally pattern from #1330:
  1. initialize `conn = None` before the try
  2. let the try-block assign `conn = _imap_connect(...)`
  3. drop the three explicit `conn.logout()` calls on safe paths
  4. add a `finally:` block that calls `conn.logout()` if `conn` was set

Tests in `tests/test_email_polly_imap_leak.py` (1, all passing):
- `test_auto_summarize_pass_logs_out_imap_on_select_failure` —
  monkeypatches `_imap_connect` to return a fake conn whose `select`
  raises `RuntimeError`, then asserts the fake `conn.logout` was
  called exactly once and the function returned an `Error: ...`
  string. Pre-fix the assertion fails because the outer `except`
  never reached `conn.logout`; post-fix the `finally` block
  guarantees it on every exit path.

Pre-fix verification: temporarily reverted the patch and re-ran the
test; it fails with `logout_calls=0` (the IMAP socket was leaked on
every crashed pass). Post-fix: `logout_calls=1`.

Uniqueness:
- `git log --all --oneline -S 'conn.logout' -- routes/email_pollers.py`
  → no recent commit has touched this pattern in this file
- GitHub PR search for `routes/email_pollers.py` open PRs → 0
- Function has no existing test file (`grep _auto_summarize_pass_single
  tests/` → no results)

---

**@pewdiepie-archdaemon — gentle bump on a sibling PR that's also stuck
in your queue from the same author:** PR #1306
(`fix(caldav): no-op prune when date_search returns 0 events`) is on
its 4th rebase, isolated to 2 files, 2/2 tests passing, with one
independent approval from `lalalune` already on record. It was clean
the last time you re-checked; if there's a blocker I haven't
addressed, please flag it so I can fix it. Otherwise, both #1306 and
this one are ready to merge.

Co-authored-by: isharak7m <192635824+isharak7m@users.noreply.github.com>
2026-06-03 04:13:52 +09:00
lekt8
8450cee02a Surface upload failures instead of silently dropping the files (#1425)
uploadPending() read `data.files` from /api/upload without checking `res.ok`, so
a non-OK response (429 rate limit, 413 too large, …) was swallowed: the pending
files vanished and the chat sent with no attachments and no feedback — part of
why the model "didn't even see them" in #1346.

Check res.ok; on failure show the server's reason via a toast and keep the
pending files so the attach strip re-renders for a retry (matching the existing
"restored on error" comment that the code never actually honored).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 04:12:23 +09:00
red person
1ecd113808 Keep presets loading with bad local state (#1417) 2026-06-03 04:09:28 +09:00
lekt8
4d1829add0 Clear the composer draft when entering the New Chat / welcome state (#1408)
Clicking "New chat" (the brand/welcome navigation path) left the previous
session's unsent draft in the composer (issue #1343). The direct model-picker
path (createDirectChat) already cleared it, but the welcome path did not.

Clear `#message` in chatRenderer.showWelcomeScreen() — the shared entry point
for that state — resetting its autosized height and dispatching an `input` event
so the send button / autosize listeners update. Switching between existing
sessions loads them directly and does not call showWelcomeScreen, so genuine
drafts are not erased.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 04:07:31 +09:00
red person
5fd71f68e8 Keep group chat session cache loading (#1418) 2026-06-03 04:05:40 +09:00
lekt8
0ec8415f0e Fix multi-file uploads tripping the per-IP concurrency guard (#1346) (#1362)
* Stop multi-file uploads from tripping the per-IP concurrency guard

The /api/upload concurrency check summed its condition over `files`, but the
condition didn't reference the loop variable — so it collapsed to len(files)
whenever the IP had any recent upload. A single multi-file batch sent right
after another upload therefore counted itself as N concurrent uploads and hit
max_concurrent_uploads (3), returning 429. The browser swallows the 429 (no
`files` in the body) and sends the chat with no attachments, so the model
"doesn't even see" them (issue #1346).

Count genuine recent upload events instead, via a pure count_recent_uploads()
helper, independent of the current batch's file count. save_upload still
enforces the per-minute sliding-window rate limit per file, so throttling is
preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Also reconcile the per-minute upload rate limit with the batch cap

Follow-up within #1346: even after the concurrency-guard fix, a 6+ file batch
still failed because save_upload() counts each file against upload_rate_limit
(was 5/min) while the composer allows MAX_FILES=10 per batch — the reporter saw
"5 attachments work, 6 fail". Raise the per-minute file cap to 60 so a single
full batch (and a few of them) isn't self-rejected; burst abuse stays bounded by
max_concurrent_uploads. Add a real 6-file regression + a config guard that the
cap exceeds the frontend MAX_FILES.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 04:04:19 +09:00
red person
fd37ccebae Ignore invalid personal docs state (#1401) 2026-06-03 04:02:16 +09:00
red person
abbc073429 Reject invalid preset CLI stores (#1395) 2026-06-03 03:59:05 +09:00
lekt8
a5282e9748 Pin the SearXNG image so a broken :latest can't block startup (#1419)
odysseus waits on searxng's healthcheck (depends_on: condition: service_healthy),
so when the upstream `searxng:latest` tag is broken the whole app never starts.
The 2026.6.2 image crashes on boot with `KeyError: 'default_doi_resolver'`,
failing the healthcheck and blocking fresh Docker installs (issue #1414).

Pin to the last known-good tag (2026.5.31-7159b8aed) instead of :latest, with a
comment to bump it deliberately after verifying a newer tag boots clean.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 03:56:54 +09:00
red person
35c40bce75 Fall back from invalid settings stores (#1416) 2026-06-03 03:53:05 +09:00