Commit Graph

5 Commits

Author SHA1 Message Date
Vykos 1adf21a7e5 Scope email account workflows by owner (#1309) 2026-06-03 02:21:02 +09:00
SurprisedDuck 934bca9e48 Providers: omit temperature for OpenAI reasoning models
* fix: omit temperature for OpenAI reasoning models (o1/o3/o4/gpt-5)

These models only accept the default temperature; sending any explicit
value (even 0.0) returns HTTP 400 "Only the default (1) value is
supported". This broke two paths:

- Endpoint probing in _probe_single_model hardcodes temperature: 0.0, so
  a perfectly valid o3/gpt-5 endpoint is reported as failing in the
  Model Endpoints health check.
- Chat/stream payloads send temperature unconditionally, so a non-default
  temperature preset 400s on these models.

The code already special-cases the same model family for
max_completion_tokens, so this adds a sibling _restricts_temperature()
helper and omits the field for those models, letting the API use its
required default. gpt-4.5 is intentionally excluded (not a reasoning
model; accepts temperature normally).

Adds tests/test_llm_core_temperature.py covering the predicate and the
synchronous payload builder.

* fix: also omit temperature for reasoning models on the direct-POST paths

The first commit only covered llm_call/llm_call_async/stream_llm and the
endpoint probe. Email auto-summary, urgency-less spam classification, the
email reply-summary endpoint, and gallery vision tagging build their
OpenAI payloads inline and POST them directly (requests/httpx), bypassing
llm_core — so a reasoning model configured there would still 400 on the
temperature field. These sites already branch on _uses_max_completion_tokens,
so they're the same class; added the matching _restricts_temperature guard.

gallery_routes also gains the max_completion_tokens branch it was missing,
so gpt-5 vision tagging works end to end.

Note: email_pollers urgency scoring goes through llm_call_async and was
already covered.
2026-06-02 20:58:33 +09:00
Collin 70a71f603c Scope email calendar extraction to account owner
The email auto-calendar pass (settings.email_auto_calendar / the
extract_email_events task) scans recently received mail and lets an LLM
create / update / cancel calendar events. Two problems made it a cross-tenant,
remotely triggerable hole:

1. No owner scoping. _auto_summarize_pass(account_id=None) fans out over EVERY
   enabled account of EVERY user. For each message it fetched an upcoming-events
   snapshot with NO owner filter (all tenants' events) and handed those uids +
   titles to the extraction LLM, then executed the model's ops via
   do_manage_calendar(...) with owner=None. do_manage_calendar only filters by
   owner when owner is not None, so create/update/delete ran across ALL users'
   calendars. Net: every user's event titles/times were disclosed to the model,
   and the model could cancel/move/duplicate any tenant's events by uid.

2. No prompt-injection wrapping. The raw email From/Subject/body were
   interpolated straight into an instruction-shaped extraction prompt (unlike
   the chat path, which wraps external text via src/prompt_security). Anyone
   who can email a user whose instance has auto-calendar enabled could inject
   operations: create attacker-controlled "meeting" events (the path even
   auto-harvests URLs from the body into the event location/description — a
   phishing primitive) or cancel/modify the victim's real events, with zero
   human in the loop.

Fix:
- Add core.database.get_upcoming_events(owner) and use it for the snapshot, so
  the LLM only ever sees the processed account owner's events.
- Look up the EmailAccount owner in _auto_summarize_pass_single and pass owner=
  to every do_manage_calendar call, so create/update/delete are scoped to that
  user (owner=None stays the single-user / legacy escape hatch).
- Tell the extraction model the email is untrusted data and not to follow
  instructions inside it (defense-in-depth against injection).

Add tests/test_calendar_owner_scope.py: get_upcoming_events returns only the
given owner's events (and everything when owner is None). Fails against the old
unscoped query.
2026-06-01 23:12:32 +09:00
pewdiepie-archdaemon 5ed9b74cd0 Polish email tasks and window controls 2026-06-01 20:56:46 +09:00
pewdiepie-archdaemon e5c99a5eee Odysseus v1.0 2026-05-31 23:58:26 +09:00