Commit Graph

1069 Commits

Author SHA1 Message Date
Wes Huber b9a96bca1a fix(research): avoid double split() call and potential IndexError (#2229)
cat.split()[0] was called in the condition and again in the body,
wasting a second split. More importantly, if cat were ever
whitespace-only, split() returns [] and [0] raises IndexError.
Assign to a local variable and guard with a truthiness check.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-07 16:46:21 +02:00
Wes Huber 706ea6a7b7 fix: TOCTOU race in personal file delete + IndexError on whitespace cmd (#2228)
1. routes/personal_routes.py: os.path.exists() then os.remove() is a
   classic TOCTOU race — another request or cleanup can delete the
   file between the check and the remove, raising FileNotFoundError.
   Replace with try/except FileNotFoundError.

2. src/tool_implementations.py: cmd.split()[0] crashes with IndexError
   when cmd is a non-empty whitespace-only string (split() returns []).
   Guard with (cmd.split() or [''])[0].

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-07 16:44:26 +02:00
M57 12cb39cbd9 feat: add OpenCode Zen and Go as provider options (#26)
- Add OpenCode Zen (https://opencode.ai/zen/v1) and Go (https://opencode.ai/zen/go/v1)
- Add provider detection via _host_match() in llm_core.py
- Add curated model list entries in model_routes.py
- Add webhook provider URLs
- Add provider icon (providers.js) and dropdown options (index.html)
- Add auto-detection patterns and setup URLs (slashCommands.js)
- Whitelist opencode.ai in URL validation (admin.js)
- Rebased on main to fix merge conflicts with _HOST_TO_CURATED refactor

Co-authored-by: M57 <hy4ri@users.noreply.github.com>
2026-06-07 16:43:00 +02:00
max-freddyfire 43c16fc7e4 fix(context_compactor): return original messages when compaction summary fails (#2174)
On summary LLM call failure, maybe_compact was returning system_msgs+recent
(dropping the older half) with was_compacted=False, misleading the caller into
thinking the list was unchanged. Return the original messages list unchanged so
no history is lost; the next trim_for_context call handles length if needed.

Fixes #2160

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 16:40:16 +02:00
SurprisedDuck c75d3e1975 fix(memory): record dislikes as dislikes, not preferences (#2435)
_fallback_memory_candidates matched both positive (prefer/like/love) and
negative (hate / do not like / don't like) sentiment verbs in one regex
alternation, then formatted every hit as "User prefers {X}.". So
"I hate cilantro" was stored as "User prefers cilantro." -- the inverse of
what the user said. These fallback facts are persisted to memory and later
re-injected into the model's context, so the inverted preference actively
misleads the assistant.

Capture the matched verb and branch on it: negatives become
"User dislikes {X}.", positives stay "User prefers {X}." (still filed under
the existing "preference" category).

Supported by Claude Opus 4.8

Co-authored-by: SurprisedDuck <288741682+SurprisedDuck@users.noreply.github.com>
2026-06-07 16:36:07 +02:00
Maruf Hasan 3c924b8dee fix: hide Select buttons in Memory/Skills tabs when list is empty (#2906)
* fix: hide Select buttons in memory/skills tabs when list is empty

* fix: disable Select buttons instead of hiding them when list is empty

* fix: dim disabled Select button and remove focus outline

* fix: reload skills after single deletion so count and toolbar stay in sync

* fix: lower minimized-dock z-index from 10020 to 100 so modals stack above it

* Revert "fix: lower minimized-dock z-index from 10020 to 100 so modals stack above it"

This reverts commit 5b092ee6cd.
2026-06-07 16:29:04 +02:00
YotamPeled adbcb3763f fix(agent): don't abort legitimate tool batches as runaway loops (#3183)
The loop-breaker's runaway backstop counted per-tool-type call totals and
tripped whenever any tool was used >=15 times — treating 15+ DISTINCT calls
to one tool as a stuck loop. A real batch (e.g. "add these 18 birthdays to my
calendar" emits 18 distinct manage_calendar create_event calls in one round)
got flagged "calling manage_calendar over and over", the calls were discarded
(next round tools_sent=0), and 0 events were created.

Count IDENTICAL repeated call signatures instead (same tool AND args), via a
small, unit-testable _detect_runaway_call() helper. Genuine batches pass; a
model truly stuck repeating one call still trips the backstop. Adds a
regression test.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 16:16:17 +02:00
michaelxer bdf4ec8b24 fix: fall back to /models probe when base URL returns 404 (#3205)
_ping_endpoint() probes the bare base URL for non-Ollama endpoints.
OpenAI-compatible servers like llama-swap return 404 on the /v1 prefix
but 200 on /v1/models, causing endpoints to appear offline despite being
fully functional.

Add a /models fallback when the base URL returns a non-auth 4xx.
Auth failures (401/403) are treated as definitive — probing /models
would just repeat the same rejection.

Fixes #3181

Co-authored-by: michaelxer <michaelxer@users.noreply.github.com>
2026-06-07 16:09:33 +02:00
danielroytel 5d3e3c7053 feat(tasks): assign folder='Tasks' at creation + backfill migration (#2834)
* feat: assign folder='Tasks' to task sessions at creation

Task sessions (LLM, action, research) now set folder='Tasks' on their
DbSession row, matching the pattern used by the Assistant folder. This
enables sidebar lens filtering without changing existing session
behaviour.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add backfill script for task session folders

One-shot script to set folder='Tasks' on existing [Task]/[Research]
sessions that predate the folder assignment in task_scheduler.py.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: replace standalone backfill script with automatic migration

Convert scripts/backfill_task_folders.py into _migrate_backfill_task_folders()
in core/database.py, called from init_db(). The migration is idempotent (only
touches rows where folder IS NULL/empty) and runs automatically on upgrade,
so operators no longer need a manual step to tag pre-existing task sessions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-07 15:33:17 +02:00
Marius 04d6a5ccaa Fix: CORS preflight 401'd by AuthMiddleware before CORSMiddleware (#3262)
AuthMiddleware is the outermost middleware, so a credential-less CORS preflight
(OPTIONS + Access-Control-Request-Method) was rejected with 401 before
CORSMiddleware could answer it. That blocks every cross-origin browser/WebView
client: the preflight fails, so the real request is never sent.

Let a genuine preflight through at the top of AuthMiddleware.dispatch via a pure,
unit-tested predicate (core.middleware.is_cors_preflight). Precise -- only
OPTIONS carrying Access-Control-Request-Method; a credentialed request is never
matched -- and no data access.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:23:23 +02:00
RaresKeY a3784da172 fix: block app_api access to shell routes (#3225) 2026-06-07 15:19:08 +02:00
Ashvin cbbb41dfb1 fix: avoid double bcrypt on login by using create_session_trusted (#3236)
* fix: avoid double bcrypt on login by adding create_session_trusted

* fix: update test to expect create_session_trusted instead of create_session
2026-06-07 15:10:53 +02:00
Vykos 83b0ab7cd3 Scope auxiliary LLM endpoints by owner (#2996)
* fix(auth): scope auxiliary llm endpoints by owner

* fix(auth): scope auxiliary llm fallbacks by owner
2026-06-07 14:47:44 +02:00
Ashvin 12a7e741d0 fix: redirect /login to / when AUTH_ENABLED=false (#3235) 2026-06-07 14:17:21 +02:00
Léo 573d431399 fix(cookbook): don't infer server OS from the browser's user-agent (#3223)
_getPlatform('local') fell back to navigator.userAgent to decide the
*server's* platform. On a Mac/Linux homeserver opened from a Windows
browser this returned 'windows', so the GGUF serve builder emitted the
Windows python-only shape (`python -m llama_cpp.server`, no
`llama-server ||` fallback). That command fails on the Unix host with
"No module named llama_cpp" even though native llama-server is installed,
and the diagnosis then misleadingly tells the user to pip-install
llama-cpp-python.

Trust the server-side hardware probe over the user-agent: a non-empty
probe backend (metal/cuda/rocm/cpu_*) means a Unix server; local Windows
instead carries platform:"windows" which already sets _envState.platform
and short-circuits. Only fall back to the browser hint when there is no
server-side signal at all. Keeps #1389/#2961's local-Windows path intact.

Fixes #3221

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:20:05 +02:00
Vykos 2149f0fb67 fix(rag): forward owner through manager wrapper (#2991) 2026-06-07 12:56:57 +02:00
Vykos 83fca6ac62 fix(personal): require document privilege for rag upload (#2990) 2026-06-07 12:56:53 +02:00
Vykos 000932a6d9 fix(auth): gate api tokens from user routes (#2992) 2026-06-07 12:55:01 +02:00
Vykos 299538ea4e Harden note reminder dispatch ownership (#2999) 2026-06-07 12:52:27 +02:00
Vykos 67aeea4f8b Scope gallery image endpoints by owner (#3001) 2026-06-07 12:51:21 +02:00
Vykos f2a79aaf5c Tighten manage notes owner checks (#3002) 2026-06-07 12:50:10 +02:00
Vykos a6490ffb1b Harden gallery album assignment scope (#3004) 2026-06-07 12:49:03 +02:00
Vykos 06d28e23ac Scope document session links by owner (#3005) 2026-06-07 12:47:20 +02:00
Vykos 7b4e6c4c1b Enforce task chain owner scope (#3006) 2026-06-07 12:43:43 +02:00
Vykos 3cff06781e Scope model helper endpoint resolution (#3007) 2026-06-07 12:40:23 +02:00
Vykos ff4508d396 Scope vision model resolution by owner (#3009) 2026-06-07 12:39:02 +02:00
ooovenenoso c11ce66e0e docs: note dev branch status in README (#3196) 2026-06-07 12:16:14 +02:00
Lucas Daniel 34bd8f0491 fix(email): guarantee IMAP conn.logout() on all exception paths (#1530)
Three IMAP connection leaks were recently fixed via try/finally
(#1325, #1330, #1423). This commit applies the same pattern to the
remaining callsites that still used inline logout-only cleanup.

routes/email_helpers.py:
- _fetch_sender_thread_context: conn was uninitialized when the outer
  try/except returned early on connect failure, causing the finally
  block to crash on conn.close()/conn.logout(). Merged the two
  separate try blocks into one and added conn=None guard.
- _pre_retrieve_context: ctx_conn.logout() was inside the loop body
  with no finally, so any exception in the folder/search loop leaked
  the socket. Moved cleanup into a finally block with ctx_conn=None
  guard.

mcp_servers/email_server.py:
- _list_emails: multiple inline conn.logout() calls on early-return
  paths; exception between them leaked the socket. Wrapped in
  try/finally.
- _read_email: same pattern — four separate logout() calls replaced
  by a single finally block.
- _reply_to_email: logout() called before the error check, so an
  exception in conn.select() leaked the socket. Wrapped in
  try/finally.
- _download_attachment: same pattern as _reply_to_email.

Also adds tests/test_imap_leak_fixes.py with 9 regression tests (one
per function/failure-mode) that monkeypatch _imap_connect and assert
conn.logout() is called exactly once even when IMAP operations raise.
2026-06-07 05:09:28 +01:00
Joeseph Grey f78539ba15 fix(caldav): disable redirects on the sync/write-back DAVClient (SSRF) (#2663)
validate_caldav_url resolves and vets the initial host, but caldav's
niquests session follows 3xx redirects by default, so a validated public
URL can be redirected at request time to loopback/link-local/private
space, re-opening the SSRF the host check closes. The existing redirect
guard only covered the settings test-connection path.

Add a shared _build_dav_client helper that pins the session to zero
redirects (any 3xx then raises instead of silently following an
attacker-chosen Location), and route both the pull (_sync_blocking) and
write-back (_writeback_blocking) paths through it. Mirrors the
follow_redirects=False already used on the test-connection path.

Tests exercise the real DAVClient request path (a 302 toward an internal
host is refused, the sink is never contacted; the PROPFIND is asserted to
reach the public server first so the check can't pass vacuously), confirm
the helper disables redirects on the installed client, guard against a
raw DAVClient creeping back in, cover mixed public/internal DNS results
in both orderings, and add the resolves-to-no-usable-records fail-closed
branch.
2026-06-07 05:05:24 +01:00
Giuseppe 95c2dca4b5 fix(security): add HSTS and Permissions-Policy to SecurityHeadersMiddleware (#3081)
* fix(security): add HSTS and Permissions-Policy headers to SecurityHeadersMiddleware

Strict-Transport-Security is sent only when the connection is HTTPS
(detected via request.url.scheme or X-Forwarded-Proto: https), so
plain-HTTP dev deployments behind a reverse proxy are unaffected.

Permissions-Policy disables camera, microphone, and geolocation APIs
unconditionally — Odysseus does not use them, and this prevents a
successful XSS from requesting browser-native sensor access.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(security): scope Permissions-Policy microphone directive to same-origin

Reviewers on PR #3081 (alteixeira20, NubsCarson) flagged that
microphone=() blocks mic access for same-origin (self) too, breaking
Odysseus's own voice/STT flow (getUserMedia({audio: true}) in
static/js/voiceRecorder.js). Scope it to microphone=(self) so
third-party origins stay locked out while the app's own UI keeps mic
access; camera and geolocation remain fully disabled as unused.

Adds focused middleware tests covering HSTS scoping (HTTPS direct,
X-Forwarded-Proto, absent on plain HTTP) and the Permissions-Policy
same-origin microphone contract.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 04:58:33 +01:00
Karandeep Bhardwaj 3940297655 fix(webhooks): redact IPv6 addresses in sanitized error messages (#3038)
* fix(webhooks): redact IPv6 addresses in sanitized error messages

sanitize_error() only stripped IPv4 literals, so a failed webhook
delivery to an internal IPv6 host (::1, fe80::/fc00:: ...) leaked the
address into Webhook.last_error, which is surfaced in the UI. The module
already treats internal IPv6 as sensitive (see _PRIVATE_NETWORKS and
src/url_safety.py); the scrubber just didn't keep up.

Add an IPv6 redaction pass covering bracketed, full 8-group, and
::-compressed forms. The pattern is scoped to leave clock times
("12:34:56"), MAC addresses, and C++ "::" tokens untouched, and the
::-branch uses a lookahead over a flat character class so there is no
nested quantifier to backtrack on (no ReDoS on long colon/hex runs).

Adds tests/test_webhook_sanitize_error_ipv6.py.

* webhook: validate IPv6 candidates with ipaddress, not a regex grammar

Per review on #3038: instead of hand-rolling the IPv6 grammar in a regex
(brittle, and easy to over-match colon-heavy text), use a loose regex to
find candidate tokens and let ipaddress.ip_address() decide. Only tokens
it parses as IPv6 are redacted, so the false-positive guards (clock times,
MACs, "std::vector") now come from the stdlib instead of a custom pattern.

This also covers cases the old pattern missed -- zone ids (fe80::1%eth0)
and IPv4-mapped addresses -- and no longer partially mangles invalid
colon strings (a 9-group token is preserved whole rather than losing its
first 8 groups). The bracketed branch is a single greedy class with no
X*:X* backtracking; verified ~1ms on 40k-char adversarial input.

Extends the test file with zone-id, IPv4-mapped, and invalid-token cases.

* webhook: redact bracketed/scoped/IPv4-mapped IPv6 as one unit

Review on #3038 found a few IP forms left partially redacted or malformed
by sanitize_error():

  [fe80::1%eth0]:8080        -> [[redacted]]:8080
  [::ffff:192.168.0.1]:8080  -> [[redacted][redacted]]:8080
  ::ffff:192.168.0.1         -> [redacted][redacted]

Two causes: the bracketed branch's character class dropped zone ids, so
scoped addresses fell through to the bare branch and left the brackets and
port behind; and the IPv4 pass ran first, stripping the embedded v4 of an
IPv4-mapped address so the v6 pass then redacted the "::ffff:" remnant
separately.

Fix:
- run the IP-candidate pass before the IPv4 pass, so IPv4-mapped forms are
  matched and redacted whole
- match the full bracketed authority ([...] + optional %zone + :port) as a
  single token, and redact a v4-or-v6 literal inside [ ] as one [redacted]
- extend the bare branch with a bounded (exactly-3) dotted-quad tail for
  IPv4-mapped forms; exactly-3 so it can't swallow a partial suffix and
  accidentally preserve an otherwise-valid address

Each form now collapses to a single [redacted]; the candidate finder stays
linear (~1.3ms on 40k-char adversarial input). Adds regression tests for
the three reported forms and keeps the timestamp/MAC/std::vector coverage.
2026-06-07 04:55:33 +01:00
Nicholai a3cb15d0a1 fix(agent): enforce guide-only tool policy (#3088) 2026-06-06 18:48:24 -06:00
@aaronjmars 108ee1e32b fix(security): close DNS-rebinding hole on diffusion_server (wildcard CORS + missing Host check) (#347)
* fix(security): close DNS-rebinding hole on diffusion_server

scripts/diffusion_server.py used to ship `allow_origins=["*"]` with the
default `--host=127.0.0.1` bind. Combined, that left the OpenAI-compatible
image API reachable from any browser tab via DNS-rebinding: an attacker page
resolves its own domain to 127.0.0.1 mid-fetch, the browser forwards the
request to the loopback server, the server processes it (no Host check), and
the wildcard CORS reply lets the attacker page read the result + drive the
GPU. CWE-346 + CWE-942 + CWE-352 (DNS-rebinding bridge).

Fix:
  - Drop the wildcard CORS at module load (default-deny).
  - Install `TrustedHostMiddleware` with a loopback allowlist so DNS-rebound
    requests are rejected by the middleware before any route runs.
  - Add additive `--allowed-host` / `--allowed-origin` CLI flags so operators
    who need browser access on a specific origin can opt in explicitly without
    re-introducing the wildcard.

Tests: tests/test_diffusion_server_security.py (9 cases) pin the allowlist
helpers, the default-deny CORS behavior, and the live middleware paths via
Starlette's TestClient.

Detected by Aeon + semgrep + manual review.
Severity: medium.
CWE-346 / CWE-942 / CWE-352.

* test(diffusion-server): drive ASGI app via httpx, not TestClient portal

The TrustedHost/CORS integration tests used `with TestClient(app) as
client:`, whose context-manager form spins up an anyio blocking portal to
run the app lifespan. Under the repo's pytest setup (anyio plugin active, a
stray asyncio_mode option, no pytest-asyncio) that portal deadlocks —
`test_trusted_host_middleware_rejects_attacker_host` hung indefinitely in
review before emitting any assertion output.

Replace the TestClient usage with a tiny _asgi_get() helper that drives the
ASGI app over httpx.ASGITransport on a fresh event loop (asyncio.run). No
portal, no lifespan, no dependency on the host project's async test plugins.
Host is taken from the request URL so TrustedHostMiddleware sees the exact
hostname under test; Origin goes through headers. Assertions are unchanged.

Focused test now passes in 0.12s; full file 9 passed.

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

---------

Co-authored-by: aeonframework <aeonframework@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 23:34:39 +01:00
muhamed hamed b03d934ec6 fix: restore backup import after skills migration (#2980) 2026-06-06 21:46:32 +01:00
Lucas Daniel eb840459f5 ci: skip pytest smoke on documentation-only changes (#2768)
* ci: skip pytest smoke on documentation-only changes

Adding paths-ignore for **.md and docs/** so that PRs that touch only
markdown files do not trigger the full pytest suite. Runner minutes are
spent only when Python or config files change.

Closes #2646.

* ci: detect docs-only changes inside the job instead of paths-ignore

Previously paths-ignore on the pull_request trigger caused the entire
workflow to be skipped, which can leave required checks pending and block
merging. Instead, keep the workflow always-triggered and detect docs-only
changes inside python-tests with a git diff step; if every changed file
is a .md or docs/ path, the step reports success without running pytest.

The syntax jobs (python-syntax, node-syntax) are cheap enough to always run.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 16:00:46 +01:00
Mohammed Riaz 6ccd4500d7 fix(chat): show requested and actual reply models
Show requested and actual reply models in chat labels when fallback or provider routing changes the responding model.
2026-06-06 04:30:16 -06:00
Merajul Arefin 2e37d72155 fix(chat): stop code-block button flicker during streaming (#3023)
Render streamed markdown incrementally (freeze finalized blocks,
re-render only the growing tail) instead of re-rendering the whole
message every token, which recreated every <pre> and dropped CSS :hover.
2026-06-06 04:08:54 -06:00
Ocean Bennett fb9c7cf3da fix(calendar): accept list event range aliases 2026-06-06 03:47:18 -06:00
Nicholai 33edc40eae fix: route misfenced web lookups to web tools
Fixes #3067
2026-06-06 03:46:31 -06:00
Giuseppe e87a1ad8d2 fix(deep-research): wrap fetched webpage content in untrusted-context sandbox
The goal-based extractor passed raw fetched webpage content straight
into the LLM prompt via string substitution, bypassing the
prompt-injection hardening layer in src/prompt_security.py.

Split EXTRACTOR_PROMPT into EXTRACTOR_SYSTEM (task instructions +
goal, trusted) and a second message built with untrusted_context_message()
(raw page content, sandboxed with <<<UNTRUSTED_SOURCE_DATA>>> guards).
This aligns the extractor with every other external-content injection
site in the codebase (agent_loop, chat_processor, chat_routes).

Fixes #3044

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 03:37:10 -06:00
Giuseppe 893cb8254f fix(sessions): retry resumeStream in poll loop when chatModule loads late
sessions.js executes before chat.js in ES module order, so
window.chatModule is not yet set when _checkServerStream runs on page
load. The resumeStream guard evaluates false and the spinner fallback
kicks in; that fallback only polls stream_status and never retries the
live-resume path, leaving the user with a dead spinner for the entire
duration of the detached agent run.

Fix: add a one-shot retry in the polling loop. On the first tick where
window.chatModule.resumeStream is available, attempt to attach. If it
succeeds, clear the interval and remove the spinner — live SSE streaming
takes over. If the run has already finished (404), the loop continues to
poll status and calls selectSession on completion.

Fixes #3048

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 03:36:30 -06:00
Maruf Hasan 870ae2823f fix: lower minimized-dock z-index so modals stack above it 2026-06-06 03:35:48 -06:00
Nicholai 86abcb75d0 fix: split Chroma embedding lanes (#3046) 2026-06-06 03:17:19 -06:00
Nicholai 463713c2c6 feat(search): unify session transcript search (#2877) 2026-06-05 18:08:31 -06:00
Mateus Oliveira c2017fa089 Phase 1: consolidate tool output constants into src/constants.py (#2989)
MAX_OUTPUT_CHARS, MAX_READ_CHARS, and MAX_DIFF_LINES are now
defined once in src/constants.py and imported by the three files
that previously duplicated them (tool_execution.py,
tool_implementations.py, agent_tools.py). agent_tools.py re-exports
them for backward compatibility.

Co-authored-by: mcnoliveira <mcnoliveira@gmail.com>
2026-06-05 23:05:02 +02:00
michaelxer 53fd856ea8 fix: raise imaplib line limit for large mailboxes (#2895)
Python's imaplib._MAXLINE defaults to 1 MB. Mailboxes with tens of
thousands of messages exceed this on UID SEARCH ALL, crashing with
'got more than 1000000 bytes'.

Set _MAXLINE to 50 MB after opening the connection so large mailboxes
work without error.

Fixes #2883

Co-authored-by: michaelxer <michaelxer@users.noreply.github.com>
2026-06-05 22:59:35 +02:00
Fijar Lazuardy 66599b02a2 allow user who disable auth to use chat (#2548)
* allow user who disable auth to use chat

* only check non user on verify session owner

* fix import source

* rollback 401 to 403 for unauthorized error due to unit test

* change unauthenticated http code error to 401 and fix unit tests
2026-06-05 22:54:19 +02:00
n2b12 fb3e89b011 VRAM detection under native Windows install (#1610)
* Convert to different style of comment to make it easier to work with, fix formatting inside Powershell script.

* Grab VRAM amount from driver's registry keys.

* Fixed regression on NVIDIA GPUs
2026-06-05 22:49:47 +02:00
Logan Davis f72e1bd412 feat(reminders): add generic webhook as a fourth reminder channel (#2952)
Replaces any Discord-specific reminder channel with a generic outbound
webhook channel. Users pick any saved Integration as the target and
supply a JSON payload template with {{title}} and {{message}}
placeholders — values are JSON-escaped before substitution. Works with
Discord, Slack, Teams, ntfy (JSON mode), or any service that accepts a
POST with a JSON body.

- `src/settings.py` — reminder_webhook_integration_id +
  reminder_webhook_payload_template defaults
- `routes/note_routes.py` — webhook delivery block; Integration lookup,
  template rendering, auth wiring; built-in preset defaults so
  discord_webhook works out of the box without a configured template;
  settings_override kwarg avoids test-button race condition
- `routes/auth_routes.py` — discord_webhook preset test handler
- `src/integrations.py` — discord_webhook preset with description +
  example templates; hides auth/key fields in the Integration form
- `src/builtin_actions.py` — webhook_sent delivery check
- `src/tool_implementations.py` — webhook aliases + enum updated
- `static/index.html` — Webhook channel option; Integration picker +
  payload template textarea
- `static/js/settings.js` — Integration list, populateWebhookIntegrations,
  syncChannelRows, hints, load/save, auto-fill preset templates,
  test-button override payload, hide auth/key for URL-auth presets

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 22:47:57 +02:00
ooovenenoso 2bdf43b74d feat(cookbook): add Gemma4 thinking chat template (#2955)
* feat(cookbook): add Gemma4 thinking chat template

* fix(cookbook): place Gemma4 thinking token in system turn
2026-06-05 22:43:31 +02:00