Skip to content

feature: allow a watch or group to append to the inherited AI Change Summary prompt - #4294

Merged
dgtlmoon merged 3 commits into
dgtlmoon:masterfrom
snowyukitty:feature/4251-llm-prompt-append-mode
Aug 20, 2026
Merged

dgtlmoon merged 3 commits into
dgtlmoon:masterfrom
snowyukitty:feature/4251-llm-prompt-append-mode

Conversation

@snowyukitty

Copy link
Copy Markdown
Contributor

Summary

Closes #4251.

Adds a per-watch and per-group radio choosing whether the AI Change Summary prompt replaces the prompt it inherits (today's behaviour, still the default) or is appended to it.

The reporter's case: they only want to add one line to the global prompt, but the only way to do that today is to paste the whole global prompt into the watch and edit it. That copy then goes stale the moment the global prompt is edited.

Behaviour

get_effective_summary_prompt() now builds the prompt from the bottom of the cascade upward — hardcoded fallback → global default → tag → watch — and each level with a value either replaces what it inherited or appends to it, per its own llm_change_summary_mode.

tag mode / value watch mode / value effective prompt
— — global default (or hardcoded fallback)
— replace WATCH WATCH
— append WATCH GLOBAL + WATCH
replace TAG append WATCH TAG + WATCH
append TAG append WATCH GLOBAL + TAG + WATCH
append TAG replace WATCH WATCH

A watch in append mode appends to whatever it would otherwise have inherited, so a group prompt stays authoritative for its watches. Levels are joined with a blank line.

Nothing changes for existing installs. replace is the default at every level, and with every level on replace the new code reduces to the original first-non-empty-wins cascade. Watches stored before this change have no mode key at all and are treated as replace — there is a test pinning exactly that.

Because the mode feeds get_effective_summary_prompt(), and that result is already part of the summary cache key, toggling the mode invalidates cached summaries automatically rather than silently serving one generated under the other mode. Also covered by a test.

Scope

  • Applies to llm_change_summary only. llm_intent has no global default to append to, and the issue and its screenshot are about the summary prompt.
  • The mode radio is on both the watch edit page and the tag/group edit page — a group appending to the global prompt is the same problem one level up.
  • llm_change_summary_mode is added to the OpenAPI spec, otherwise it would come back from a GET /api/v1/watch/<uuid> and then be rejected by the unknown-field validator on the PUT round trip.

One thing I deliberately left alone: the existing Modify default prompt button pastes the inherited prompt into the textarea, which is a replace-mode workflow and would duplicate the prompt if clicked while append is selected. Hiding it in append mode needs JavaScript in a template shared by watch and tag edit, so I left it out rather than grow the diff — happy to add it if you'd like.

Testing

New tests, all passing:

  • tests/llm/test_evaluator.py::TestSummaryPromptAppendMode — 9 unit tests over the cascade: append onto global, onto the hardcoded fallback, onto a tag; the tag+watch chain; append with empty text; a missing mode key behaving as replace; and the cache key changing with the mode.
  • tests/test_llm_change_summary.py — 3 integration tests: append mode saved through the watch edit form and applied; a pre-[feature] Per-site appending to the global LLM prompt, instead of only overwriting it #4251 form submission (no mode field) still replacing; the radio rendering on the edit page.
  • tests/test_llm_group_overrides.py — 2 tests: the radio rendering on the tag edit page, and a group in append mode adding to the global prompt.

Suite runs on this branch (Linux container):

  • tests/llm/ tests/unit/ tests/test_llm_change_summary.py tests/test_llm_group_overrides.py — 375 passed
  • tests/test_api.py tests/test_api_openapi.py tests/test_api_tags.py — 25 passed
  • tests/restock/ tests/test_notification.py — 11 passed, 1 failed

The one failure is tests/restock/test_restock.py::test_restock_detection, which fails identically on unmodified master in the same environment — unrelated to this change.

CI gates run locally: ruff check . --select E9,F63,F7,F82,INT clean, OpenAPI spec validates, and the template i18n fragmentation check stays at the baseline of 44 with no new violations. The new UI strings are wrapped in _l()/_(); I have not regenerated the translation catalog, to keep this diff free of .mo/.pot churn (#4108).

@dgtlmoon
dgtlmoon merged commit 01cf56c into dgtlmoon:master Aug 20, 2026
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] Per-site appending to the global LLM prompt, instead of only overwriting it

2 participants