Commit Graph

701 Commits

Author SHA1 Message Date
pewdiepie-archdaemon 3706d756f3 Merge remote-tracking branch 'origin/main' into visual-pr-playground
# Conflicts:
#	routes/cookbook_routes.py
#	routes/hwfit_routes.py
#	services/hwfit/fit.py
#	services/hwfit/models.py
#	static/js/cookbook-diagnosis.js
#	static/js/cookbook-hwfit.js
#	static/js/cookbook.js
#	static/js/cookbookRunning.js
2026-06-03 16:49:10 +09:00
pewdiepie-archdaemon eb79b76432 Cookbook: scoring fixes, UI polish, false-finished + stale-state bug fixes
Backend (services/hwfit + routes):
- rank_models picks visible set by REQUESTED column, not always score —
  sorting by Param now shows highest-param models PERIOD (incl. too_tight).
- New fit_only param. Multi-GPU rigs filter GGUF Q*/IQ quants (vLLM/SGLang
  cannot serve them); default non-prequantized to BF16 on 2+ GPUs.
- AWQ / GPTQ-8bit get a -1.0 quality penalty (was 0.0, tied with FP8), so
  FP8 wins when both fit.
- Version-aware tiebreaker (parse Mn.n / Vn) — MiniMax-M2.7 ranks above
  M2.5 on equal composite score; >=100B integers not misread as versions.
- /api/cookbook/hf-latest no longer drops models without an "NB" pattern in
  the repo id (MiniMax-M2.7, DeepSeek-V4-Pro etc. were silently filtered).
- Cached-model scan: atexit flushes models JSON even if the script is
  killed mid-walk; each scan_dir wrapped in try/except; timeout 60s -> 180s.
- KB granularity for sub-MB sizes (was "0 MB" for 12 KB shells). New
  "stalled" status for shells <1 MB with no .incomplete files.
- /api/cookbook/state POST guard: rejects "done" download tasks lacking
  DOWNLOAD_OK / DOWNLOAD_FAILED / /snapshots/ when the last-mentioned
  shard is N<total — stops stale tabs from poisoning persisted state.
- hf_models.json: add zai-org/GLM-5.1; flip zai-org/GLM-5 quantization
  Q4_K_M -> BF16 (it is the native base, not a quant).

Frontend (static/js):
- Scan/Download toolbar: quant defaults to All; ctx slider (8k/16k/32k/
  50k/128k/Max) ported from origin/main with sort=fit on drag, sort=score
  on Max. GPU toggle commits _activeCount to maxGpu on initial render. Fit
  column header tagged with active budget (RAM / GPU / N GPU).
- Foldable Download admin-card: the Download h2 is the chevron trigger;
  state persists in localStorage.
- Download card surfaces destination dir (Dir: <path>). Same dir on running
  task row, font/color matched to uptime (9px Fira Code muted, opacity .4).
- Serve panel ctx text input always resets to model max on open. Sub-MB
  cached models show with red "download stalled" badge.
- Bulk-select Cancel + Delete reset the Select button label on exit.
- Cookbook running: false-finished bug fixed — DOWNLOAD_OK or /snapshots/
  required; bare "Download complete" no longer marks the task done after
  the first config file. Clear button now sends tmux kill-session too.
  True overall % for multi-shard downloads: ((N-1)+frac)/total instead of
  hf_transfer per-shard aggregate.
- Diagnosis card simplified: removed fold toggle, copy button, dismiss X.
  Suggestion font matches message body (12px).
- HF token field flashes green check + "Saved" on save.
- Cached scan no longer counts stalled rows as downloaded in Scan/Download.

CSS:
- dep Install button width pinned to 76px to match Installed split.
- task-sub row +1px; task-status badge gets margin-right 8px.
- Ctx slider styled like gallery editor sliders (thin pill rail, red thumb).
- Bulk-select cancel button top -3px -> -5px.
2026-06-03 16:32:20 +09:00
pewdiepie-archdaemon 41a928f21b Tighten PR template and CONTRIBUTING to gate visual/style changes
The post-launch PR flood from LLM coding agents drowned the repo in PRs
that don't run the app, attach no screenshots, and invent parallel
component styling. Even tiny correctness fixes accumulated into a visual
mess. Make the rules explicit in both the PR template and CONTRIBUTING:

- Run the app and view the change in a browser before submitting.
- Required screenshot for any UI/render touch (no longer "delete if not UI").
- Explicit style requirements: reuse CSS variables, no Unicode emoji
  (use SVG icons), monospaced font, dark theme, no parallel widgets.
- Direct callout for bulk agent-generated PRs: open an issue first.

PRs that ignore these will be closed without merge, regardless of code
correctness.
2026-06-03 15:35:10 +09:00
red person 93249a14b0 Keep compact font family names together (#1263) 2026-06-03 14:24:30 +09:00
Shaw b10e6bc870 fix(cookbook): install llama-cpp-python[server] so llama.cpp serving works (#730) (#1338)
The llama.cpp serve auto-install built a bare `llama-cpp-python` in the Linux
source-build fallback and the Termux path, but the serve command runs
`python3 -m llama_cpp.server`, which needs the `[server]` extra. Because the
"already installed?" guard only checks `import llama_cpp` (a bare install
satisfies it), the missing extra was never added, so serving crashed with
`ModuleNotFoundError: No module named 'starlette_context'` (issue #730).

- Request the `[server]` extra in both the Termux direct install and the Linux
  Python-bindings fallback (the Windows path already used `[server]`).
- Shell-quote the package spec in `_pip_install_fallback_chain` via `shlex.quote`
  so the `[server]` brackets aren't treated as a bash glob; plain names unaffected.

Tests: tests/test_cookbook_helpers.py gains extras-quoting coverage and a
serve-runner regression guard.
2026-06-03 14:24:26 +09:00
Shaw 552bc15067 fix(search): degrade to empty results on non-JSON provider responses (#1129) (#1352)
tavily_search, serper_search and google_pse_search parsed response.json()
inside the network try block, which only caught httpx.RequestError and
RateLimitError. When a provider returned a non-JSON body (an HTML error page, a
truncated/empty body, a gateway 5xx), response.json() raised an UNCAUGHT
json.JSONDecodeError that aborted the search in the background — exactly the
'search engines other than SearXNG fail in the background' symptom.

brave_search already handles this correctly: it parses JSON in its own try
block and returns [] on json.JSONDecodeError. Mirror that in the other three
providers so a malformed provider response degrades to no-results instead of
propagating an exception.

Adds tests/test_search_provider_json.py: a non-JSON 200 body now yields [] for
tavily, serper, google_pse, and brave (the last guards the reference behaviour).

Co-authored-by: NubsCarson <nubs@nubs.site>
2026-06-03 14:24:23 +09:00
Shaw e678ff753f fix(email): guard _decode_header against unknown MIME charset (#1354)
A header that declares an unknown or invalid MIME charset (e.g. a malformed
or spam Subject like =?x-unknown-charset?B?...?=) raised an uncaught
LookupError. bytes.decode(..., errors="replace") only handles byte-decode
errors, not codec *lookup* failures, so the "replace" safety net did not
apply.

_decode_header decodes Subject/From/To/Cc for the inbox list, single-message
fetch, and the background mail pollers (routes/email_routes.py,
routes/email_pollers.py, src/builtin_actions.py), so a single bad message
could crash the whole inbox render or the poller loop.

Wrap the per-part decode in try/except (LookupError, ValueError) and fall
back to utf-8/replace. Valid charsets (utf-8, iso-8859-1, ...) are unchanged.

Adds tests/test_email_decode_header.py — the unknown-charset case fails
before this change and passes after.
2026-06-03 14:24:20 +09:00
Ruben G. 87fc675ccb fix(cookbook): auto-register a local endpoint when serving an LLM (#1380)
Serving a diffusion model auto-registered an image endpoint so it appeared in the model picker, but serving an LLM (llama.cpp/vLLM/SGLang/Ollama) did not — a downloaded-and-served model never showed up until the user manually ran /setup. Add _auto_register_llm_endpoint (text sibling of _auto_register_image_endpoint): parse the serve port (explicit --port, else Ollama 11434, else llama.cpp 8080), point an endpoint at http://host:port/v1, dedupe by base_url, and set supports_tools from --enable-auto-tool-choice. Wire it into /api/model/serve for any non-pip, non-diffusion serve.
2026-06-03 14:24:17 +09:00
Shaw bfbbc9b479 fix(calendar): keep recurring events with a UTC UNTIL from collapsing to one (#1383)
Events are stored with a naive (UTC) dtstart, but standard .ics exporters
(Google, Apple, Outlook, Fastmail) write the recurrence bound as an absolute
UTC value, e.g. FREQ=DAILY;UNTIL=20240105T090000Z. dateutil refuses to mix a
tz-aware UNTIL with a naive DTSTART ("RRULE UNTIL values must be specified in
UTC when DTSTART is timezone-aware"), so _expand_rrule's except branch swallowed
the ValueError and silently downgraded the event to non-recurring — every
occurrence after the first vanished from the calendar.

When dtstart is naive, strip the trailing Z from UNTIL so it matches the naive
DTSTART before parsing. No effect on tz-aware dtstarts or naive-UNTIL rules.

Adds tests/test_calendar_rrule_until_utc.py — a daily series bounded by a UTC
UNTIL expands to all 5 occurrences (fails before: returns 1, non-recurring).

Co-authored-by: NubsCarson <nubs@nubs.site>
2026-06-03 14:24:14 +09:00
Afonso Coutinho fb8a744cae fix: skill retrieval boosts on tag substrings (e.g. 'ai' tag for any 'email' query) (#1406)
* fix: match skill tags as whole tokens, not substrings, in retrieval

* test: skill tag matching uses whole tokens, not substrings

* test: give skill fixtures status=published so they reach the scoring path
2026-06-03 14:24:11 +09:00
Shaw 49bf73b228 fix(forms): keep PDF-form export from dropping values when the label has '*' (#1407)
parse_markdown_to_values — the read-back path for export-pdf, the export
preview, and prepare-signed-reply — matched the bold field label with [^*]+, so
it could not match a label containing '*' (the near-universal required-field
marker: "Email *", "State *", "Signature *"). The value then stayed empty, so
the exported PDF and the signed-reply attachment came out blank for that field
with no error — a whole form of required fields could export completely empty.

Match the label non-greedily (.+?) so '*' in labels is tolerated while still
splitting at the first ':**' / '**[', which also preserves a value that itself
contains ':**'.

Adds tests/test_form_markdown_roundtrip.py (render -> parse roundtrip): asterisk
text/choice/signature labels survive (fail before, pass after); plain labels and
colon-bearing values are unaffected.

Co-authored-by: NubsCarson <nubs@nubs.site>
2026-06-03 14:24:07 +09:00
Shaw 43ed3f7148 fix(contacts): parse Apple/iCloud item-grouped vCard EMAIL/TEL properties (#1438)
_parse_vcards matched property names with a bare line.startswith("EMAIL") /
"TEL" / "FN:" / "UID:". RFC 6350 property groups — emitted by default by Apple
Contacts / iCloud and many CardDAV servers — prefix the name with a group token,
e.g. item1.EMAIL;type=pref:jane@example.com. Those lines never matched, so emails
and phone numbers from any Apple-synced or Apple-exported address book were
silently dropped (breaking contact search by email, composer autocomplete, and
vCard/CSV export round-trips).

Strip an optional leading group token before matching and value extraction;
no-op for non-grouped lines.

Adds tests/test_contacts_vcard_parse.py (grouped + plain) — the grouped case
fails before this change and passes after.

Co-authored-by: NubsCarson <nubs@nubs.site>
2026-06-03 14:24:04 +09:00
ghreprimand 3eed73e11e Guard session message persistence after delete (#1451)
Co-authored-by: ghreprimand <203024559+ghreprimand@users.noreply.github.com>
2026-06-03 14:24:01 +09:00
Afonso Coutinho f19265742c fix: SMTP envelope recipients split on commas inside display names (#1464) 2026-06-03 14:23:58 +09:00
Alexandre Teixeira 1c2ec288dd Check cudart before llama.cpp CUDA build (#1466) 2026-06-03 14:23:55 +09:00
Afonso Coutinho b55c970ec5 fix: sports-hint ranking penalty fires on 'transport'/'passport' substrings (#1473)
* fix: sports-hint ranking penalty fires on 'transport'/'passport' substrings

* Apply word-boundary sports-hint fix to src/search/ranking.py as well
2026-06-03 14:23:52 +09:00
lekt8 ffb8fd16bc Disable pip cache for Cookbook dependency installs (off the home disk) (#1477)
Cookbook dependency installs (vLLM and friends) build large wheels; pip's
default cache lives under $HOME/.cache/pip, so on a small home filesystem the
build dies mid-way with "[Errno 28] No space left on device" (issue #1219) and
the dependency ends up "installed" but unusable (issue #1459).

Add `--no-cache-dir` to the dependency pip-install command (the maintainer's
suggested PIP_CACHE_DIR= workaround, made the default) via a small
_pip_install_no_cache() helper applied at the install chokepoint. Consistent
with the existing --no-cache-dir on the llama-cpp-python build. Idempotent;
non-pip-install serve commands are untouched.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 14:23:49 +09:00
Paulo Victor Cordeiro 1feb2ae7d5 fix: close AsyncExitStack on MCP init/tool-discovery failure (#1493)
If session.initialize() or list_tools() raises after the stdio
subprocess or SSE connection is already open, the AsyncExitStack is
never closed — leaking the child process or HTTP connection. Wrap the
setup phase in try/except to aclose() the stack before re-raising.
2026-06-03 14:23:46 +09:00
ghreprimand 8c4ea484a9 Cap inline attachment context across files (#1498)
Co-authored-by: ghreprimand <203024559+ghreprimand@users.noreply.github.com>
2026-06-03 14:23:43 +09:00
Ernest Hysa a91321d1d8 Scope core.* module stubs to the test, not the module (#1513)
Three test files (test_auth_regressions, test_auth_event_loop,
test_null_owner_gates) install stubs for core.database / core.auth /
src.endpoint_resolver at module-import time, so they outlive the
file and are still present in sys.modules when later-collected test
files try to import the real modules. The stubs are minimal (a
handful of MagicMock attrs) so the import chain that follows fails
with ImportError on the very next real import.

test_companion_pairing also leaks, with a twist: its _DBStub
subclass returns a MagicMock for *any* attribute including dunders,
so the next test that does `from core.database import *` reads
`__all__` as a MagicMock and dies with 'Item in __all__ must be
str, not MagicMock'.

Move the stub installation into an autouse fixture per file and
register each stub with monkeypatch.setitem so sys.modules is
restored to its pre-test state on teardown. Tighten _DBStub to
refuse dunder names so __all__ stays undefined. _CAPTURED is
cleared per test so the mint-token assertions see a fresh dict.

Before: 3 test files fail at collection time (test_chat_image_routing,
test_context_compactor, test_webhook_ssrf_resilience). After: 0
collection errors. 1365/1370 pass, 1 skip, 4 unrelated pre-existing
failures (verified against origin/main baseline).

Out of scope: test_task_scheduler_session_delivery::
test_session_delivery_survives_empty_database also fails in the
full suite due to order-dependent state from a different test
file. That's a separate leak with a different root cause.
2026-06-03 14:23:40 +09:00
Afonso Coutinho 0dd67143f1 fix: PDF attach uses lstrip(chars) that eats body text, not the marker helper (#1541) 2026-06-03 14:23:37 +09:00
Afonso Coutinho 6e1df4ddc6 fix: POST /api/contacts/add crashes on JSON null name/email (None.strip()) (#1544) 2026-06-03 14:23:34 +09:00
Afonso Coutinho f93755e7a4 fix: params_b crashes the whole ranking on a malformed parameter_count (#1550) 2026-06-03 14:23:30 +09:00
Lucas Daniel 398892cced fix(settings): catch PermissionError in load_settings + error-path tests (#1570)
PermissionError was not in the except tuple so an unreadable settings.json
would crash the app instead of falling back to defaults. Added alongside the
existing FileNotFoundError/JSONDecodeError/ValueError catches.

Also adds test_settings_error_paths.py covering all four failure modes:
missing file, corrupted JSON, wrong type, and permission denied.
2026-06-03 14:23:27 +09:00
Mahdi Salmanzade cbf8103cba fix(login): keep inputs >=16px on touch so iOS doesn't zoom on focus (#1632)
The login page has its own inline <style> and doesn't load static/style.css,
so it never inherited the main app's touch-device rule that pins text inputs
to 16px. Its fields are 0.95rem (~15.2px) and the dynamically-inserted 2FA
input is 14px, so iOS Safari zooms the whole page when either is focused -
on the very first screen every user sees.

Add a `@media (hover: none) and (pointer: coarse)` rule raising
`input:not(.remember-check)` to 16px, mirroring the main app's approach.
!important also lifts the 2FA input, which pins font-size:14px inline.
Desktop is unchanged (inputs stay 0.95rem).
2026-06-03 14:23:24 +09:00
Afonso Coutinho 9bd11fd6e7 fix: Mixtral and Ministral models render with no provider logo (#1640) 2026-06-03 14:23:21 +09:00
danielroytel 39848a168b fix: recognize Gemma 4 as a thinking model and add context entry (#1642)
Gemma 4 returns reasoning_content in streaming responses via
llama-server, but the model wasn't listed in _THINKING_MODEL_PATTERNS,
causing reasoning tokens to be mishandled. Add "gemma" to the pattern
list and register Gemma 4's 128K context window in KNOWN_CONTEXT_WINDOWS
so the agent loop budgets context correctly.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-03 14:23:18 +09:00
Afonso Coutinho b45611e9c5 fix: _strip_reasoning_prose discards the answer when reasoning trails it (#1643) 2026-06-03 14:23:15 +09:00
Afonso Coutinho 3e33cf6439 Anchor shell-verb intent patterns to imperative or can-you position (#1664) 2026-06-03 14:23:10 +09:00
Afonso Coutinho 8a0b79bc84 fix: deep research runs the prompt's example queries when the model echoes them (#1666) 2026-06-03 14:23:07 +09:00
Afonso Coutinho 26d040d116 fix: gallery records raw instead of display dimensions for EXIF-rotated photos (#1667) 2026-06-03 14:23:04 +09:00
Afonso Coutinho b396252af6 fix: monthly tasks scheduled for day 29-31 skip every short month (#1668) 2026-06-03 14:23:01 +09:00
Afonso Coutinho 7f80d33210 fix: services research lists junk no-content pages as cited sources (#1669) 2026-06-03 14:22:58 +09:00
Afonso Coutinho eae8797e08 fix: web search content blocks numbered by fetch completion order break citations (#1672) 2026-06-03 14:22:55 +09:00
Ethan 202df9dcde Fix HTTP 500 in history routes: order ChatMessage by timestamp, not created_at (#1673)
The mark-stopped, update-last-meta, and merge-last-assistant handlers in
routes/history_routes.py ordered ChatMessage queries by
DbChatMessage.created_at. ChatMessage does not inherit TimestampMixin and
has only a `timestamp` column, so SQLAlchemy raised AttributeError at
query-build time -> HTTP 500 on Stop, last-message metadata updates, and
Continue/merge. Each handler mutates in-memory history before the failing
query, so a failed request also silently diverged the in-memory view from
the database.

Order by DbChatMessage.timestamp (already used elsewhere in the file and
covered by the ix_messages_session_time index). Add a regression test
pinning the model column reality, the corrected query, and a guard against
re-introducing created_at.

Fixes #1659

Co-authored-by: Ethan <23321960+0xLeathery@users.noreply.github.com>
2026-06-03 14:22:51 +09:00
Afonso Coutinho fbb52a73a0 fix: re-importing an ICS file duplicates every tz-aware timed event (#1683) 2026-06-03 14:22:49 +09:00
Afonso Coutinho 1161040efe fix: visual report drops photos whose URL slug contains icon or logo (#1685) 2026-06-03 14:22:45 +09:00
Afonso Coutinho 3d00c85636 fix: hwfit native quant labels miss the cost maps and over-estimate VRAM (#1690) 2026-06-03 14:22:42 +09:00
red person 77b92020c0 Ignore non-string markdown table rows (#1648) 2026-06-03 14:17:02 +09:00
red person 648900612e Ignore non-string calendar date inputs (#1649) 2026-06-03 14:16:58 +09:00
red person 100fd72e7a Ignore censor preference storage errors (#1652) 2026-06-03 14:16:55 +09:00
red person 12652581cb Ignore invalid model sort inputs (#1653) 2026-06-03 14:16:52 +09:00
red person 116ade4630 Ignore non-string signature fold metadata (#1655) 2026-06-03 14:16:48 +09:00
Afonso Coutinho 96d59d2ff9 fix: _parse_dt does not understand 'tonight' so event start/end breaks (#1488) 2026-06-03 14:14:41 +09:00
Shaw eb5727abda fix(agent): coerce non-object tool-call arguments instead of crashing (#1370)
A native function/tool call whose `arguments` field is valid JSON but not an
object — a bare array like ["ls -la"], or a string/number/bool/null — parsed
fine in function_call_to_tool_block and then every branch called args.get(...),
raising AttributeError ('list'/'str' object has no attribute 'get'). That
propagated out of the streamed agent loop (no surrounding try/except at the
call site in stream_agent_loop) and aborted the user's entire turn. Weaker and
local models routinely emit malformed args like this.

Coerce non-dict parsed arguments to {} (mirrors the existing empty-arguments
behavior), so the tool runs with empty args instead of killing the stream.

Adds tests/test_function_call_non_object_args.py covering array/string/number/
bool/null arguments — they fail before this change and pass after.
2026-06-03 14:14:37 +09:00
Denis Kutuzov (Rybak27) ec3b8b42ae fix: auto-naming for 24h time format (#1374)
* fix: auto-naming for 24h time format

needs_auto_name() required AM/PM suffix for default
frontend-generated names like 'deepseek-v4-flash 17:46:02'.
Frontend uses toLocaleTimeString() which outputs 24h
format in most locales — so the regex never matched and
auto-naming silently skipped.

Made AM/PM optional and added re.IGNORECASE for 'am'/'pm'.

* test: add regression tests for needs_auto_name (24h + 12h + custom)

---------

Co-authored-by: Calculator Dev <dev@calculator.local>
2026-06-03 14:14:34 +09:00
ghreprimand 41d2767b30 Replace task scheduler utcnow calls (#1456)
Co-authored-by: ghreprimand <203024559+ghreprimand@users.noreply.github.com>
2026-06-03 14:14:30 +09:00
Marius Oppedal Ringsby 4f03f5ccdd Replace cleanup service datetime.utcnow calls (#1494)
datetime.utcnow() is deprecated in Python 3.12 and removed in 3.14.
Swap the five calls in src/cleanup_service.py for a local _utcnow()
helper returning naive UTC, matching the naive DateTime columns the
archive/delete cutoffs compare against (same approach as the
task-scheduler and core-database slices). Add a regression test
asserting the helper stays naive so the cutoff math can't hit a
naive/aware TypeError.

Part of #1116
2026-06-03 14:14:27 +09:00
ghreprimand 6fd52cf317 Replace webhook manager datetime.utcnow calls (#1499)
Co-authored-by: ghreprimand <203024559+ghreprimand@users.noreply.github.com>
2026-06-03 14:14:23 +09:00
Alexandre Teixeira c639daa7a2 Add companion pairing route response tests (#920) 2026-06-03 14:14:20 +09:00