fix: Chat-Titelmodus admin-konfigurierbar (Issue #52) #55

Merged
antonsxh merged 2 commits from fix/issue-52-title-mode into main 2026-08-15 16:40:28 +00:00
Owner

Problem (Issue #52)

Wenn kein Antwortmodus mit dem Key instant existiert (z. B. nach einem Rename), wurden Chat-Titel nie mehr generiert. Die Titel-Anfrage hatte instant hartkodiert, fiel still auf den Standardmodus zurück und scheiterte häufig an Reasoning-Modellen: Das 48-Token-Budget wurde komplett von Reasoning-Tokens verbraucht, content kam leer zurück und der Server finalisierte trotzdem New chat als endgültigen Titel.

Lösung

  • Neue Admin-Setting titleReasoningPreset (Default: auto) – der Admin wählt im Response-modes-Bereich wie beim Standardmodus einen Titelmodus (Dropdown neben „Standardmodus“, mit Option „Automatisch“).
  • auto = bisheriges Verhalten (instant → Standardmodus → erster aktivierter Modus). Umbenannte oder gelöschte Modi fallen kontrolliert auf auto zurück.
  • max_tokens: 512 für die Titel-Generierung, damit Reasoning-Modelle Platz für das JSON-Resultat haben.
  • Bei leerem/ungültigem Modell-Output antwortet der Endpoint jetzt mit 502 + transient statt Fake-Titel „New chat“ – der Client behält den vorläufigen Titel und versucht es im nächsten Turn erneut.

Geänderte Bereiche

  • src/server/config/app-settings.js, src/server/config/runtime-settings.js (Setting + Validierung/Exposition)
  • server.js (handleTitleGeneration)
  • src/ui/partials/admin.html, public/app.js, public/styles/pages/admin-experience.css (Admin-UI)
  • i18n/de.json, i18n/en.json (4 neue Keys)
  • tests/runtime-settings.test.mjs (Rename/Unknown-Choice/Fallback/Default)

Tests

  • npm run lint, test:i18n, test:docs, test:ui (Desktop + Mobile) – alles grün
  • npm run test:unit: 792 pass / 0 fail (4 Cancellations in chat-job-outcome.test.mjs sind vorbestehend und auf cleanem Checkout reproduzierbar)
  • test:security/test:api/test:e2e bewusst nicht ausgeführt (ändern Zustände / rufen Modelle auf)

Closes #52

## Problem (Issue #52) Wenn kein Antwortmodus mit dem Key `instant` existiert (z. B. nach einem Rename), wurden Chat-Titel nie mehr generiert. Die Titel-Anfrage hatte `instant` hartkodiert, fiel still auf den Standardmodus zurück und scheiterte häufig an Reasoning-Modellen: Das 48-Token-Budget wurde komplett von Reasoning-Tokens verbraucht, `content` kam leer zurück und der Server finalisierte trotzdem `New chat` als endgültigen Titel. ## Lösung - **Neue Admin-Setting `titleReasoningPreset`** (Default: `auto`) – der Admin wählt im Response-modes-Bereich wie beim Standardmodus einen **Titelmodus** (Dropdown neben „Standardmodus“, mit Option „Automatisch“). - `auto` = bisheriges Verhalten (`instant` → Standardmodus → erster aktivierter Modus). Umbenannte oder gelöschte Modi fallen kontrolliert auf `auto` zurück. - **`max_tokens: 512`** für die Titel-Generierung, damit Reasoning-Modelle Platz für das JSON-Resultat haben. - Bei leerem/ungültigem Modell-Output antwortet der Endpoint jetzt mit **502 + transient** statt Fake-Titel „New chat“ – der Client behält den vorläufigen Titel und versucht es im nächsten Turn erneut. ## Geänderte Bereiche - `src/server/config/app-settings.js`, `src/server/config/runtime-settings.js` (Setting + Validierung/Exposition) - `server.js` (`handleTitleGeneration`) - `src/ui/partials/admin.html`, `public/app.js`, `public/styles/pages/admin-experience.css` (Admin-UI) - `i18n/de.json`, `i18n/en.json` (4 neue Keys) - `tests/runtime-settings.test.mjs` (Rename/Unknown-Choice/Fallback/Default) ## Tests - `npm run lint`, `test:i18n`, `test:docs`, `test:ui` (Desktop + Mobile) – alles grün - `npm run test:unit`: 792 pass / 0 fail (4 Cancellations in `chat-job-outcome.test.mjs` sind vorbestehend und auf cleanem Checkout reproduzierbar) - `test:security`/`test:api`/`test:e2e` bewusst nicht ausgeführt (ändern Zustände / rufen Modelle auf) Closes #52
fix: make chat title generation mode admin configurable (issue #52)
Some checks failed
CI / Safe checks (pull_request) Failing after 58s
9bdb42d3c3
Renaming or removing the "instant" response mode previously broke chat
title generation: the title endpoint hardcoded that key, silently fell
back to the default (often a reasoning) mode, and the 48-token budget
was consumed by reasoning traces, so no title was ever produced.

- Add admin setting titleReasoningPreset (default: auto) exposed through
  the runtime configuration and selectable in the response-mode
  workspace like the default mode
- Title generation now routes through the admin-selected mode and fails
  with a transient 502 instead of finalizing "New chat" when the model
  returns no usable title (the client retries on the next turn)
- Raise the title token ceiling to 512 so reasoning models leave room
  for the JSON payload
- Cover rename/unknown-choice/fallback behavior in unit tests
Owner

Danke für die PR. Der konfigurierbare Titelmodus und der beabsichtigte Auto→instant-Fallback passen so. Es gibt aber noch einen Merge-Blocker: Wenn /api/title nach deiner Änderung wegen leerem Modell-Output mit 502 antwortet, schluckt generateChatTitle() den Fehler in public/app.js nur im catch. pendingTitleConversationId wurde am Aufrufort bereits gelöscht und titleRetryPending wird bei diesem Fehler nicht gesetzt. Dadurch wird entgegen der PR-Beschreibung beim nächsten substantiellen Turn nicht erneut versucht, einen Titel zu erzeugen. Bitte im Fehlerpfad für einen weiterhin vorhandenen, noch nicht betitelten Chat den Retry-Marker setzen/persistieren und einen Regressionstest ergänzen, der „erster Titelrequest schlägt fehl → nächster abgeschlossener Turn versucht erneut“ abdeckt. Der derzeit rote npm audit-Check (nanoid über Excalidraw) ist unabhängig von deiner PR und wird separat auf main behoben.

Danke für die PR. Der konfigurierbare Titelmodus und der beabsichtigte Auto→`instant`-Fallback passen so. Es gibt aber noch einen Merge-Blocker: Wenn `/api/title` nach deiner Änderung wegen leerem Modell-Output mit 502 antwortet, schluckt `generateChatTitle()` den Fehler in `public/app.js` nur im `catch`. `pendingTitleConversationId` wurde am Aufrufort bereits gelöscht und `titleRetryPending` wird bei diesem Fehler nicht gesetzt. Dadurch wird entgegen der PR-Beschreibung beim nächsten substantiellen Turn nicht erneut versucht, einen Titel zu erzeugen. Bitte im Fehlerpfad für einen weiterhin vorhandenen, noch nicht betitelten Chat den Retry-Marker setzen/persistieren und einen Regressionstest ergänzen, der „erster Titelrequest schlägt fehl → nächster abgeschlossener Turn versucht erneut“ abdeckt. Der derzeit rote `npm audit`-Check (`nanoid` über Excalidraw) ist unabhängig von deiner PR und wird separat auf `main` behoben.
Owner

Der unabhängige Audit-Fix ist jetzt mit Commit 4a5fe51 über den grünen PR #56 in main gemergt. Bitte rebasiere/aktualisiere deinen Branch auf den aktuellen main, wenn du den Retry-Fix pushst; dann übernimmt deine PR automatisch den gepatchten nanoid-Lock und die vollständige CI läuft erneut.

Der unabhängige Audit-Fix ist jetzt mit Commit `4a5fe51` über den grünen PR #56 in `main` gemergt. Bitte rebasiere/aktualisiere deinen Branch auf den aktuellen `main`, wenn du den Retry-Fix pushst; dann übernimmt deine PR automatisch den gepatchten `nanoid`-Lock und die vollständige CI läuft erneut.
antonsxh force-pushed fix/issue-52-title-mode from 9bdb42d3c3
Some checks failed
CI / Safe checks (pull_request) Failing after 58s
to ecc743a52b
All checks were successful
CI / Safe checks (pull_request) Successful in 5m23s
Container images / Build temporary amd64 candidates (push) Successful in 21m45s
Container images / Smoke-test App candidate (push) Successful in 1m5s
Container images / Smoke-test Whisper candidate (push) Successful in 53s
Container images / Publish immutable amd64 candidates (push) Successful in 45s
2026-08-15 16:34:51 +00:00
Compare
Author
Owner

Danke für die Hinweise – beide erledigt:

Retry-Fix (Merge-Blocker): Der Retry-Vertrag ist jetzt in public/js/chat/chat-title.js ausgelagert (needsTitleGeneration / markTitleRetry / clearTitleRetry). generateChatTitle() setzt und persistiert titleRetryPending auf jedem nicht-finalisierenden Pfad (kein nutzbares Assistant, kein nutzbarer Input, fehlgeschlagener Request/Catch), und der Job-Completion-Gate nutzt needsTitleGeneration(). Damit wird der 502-Fehlerpfad nicht mehr still verschluckt: der nächste abgeschlossene substantielle Turn setzt den Titel erneut an.

Rebase: Der Branch ist jetzt auf den aktuellen main (4a5fe51, gepatchter nanoid-Lock über PR #56) rebased – Commit 15c9491 (Titelmodus) + ecc743a (Retry-Fix) auf 4a5fe51. Die PR übernimmt damit automatisch den gepatchten Lock.

Tests: lint, test:i18n, test:docs, test:ui (Desktop+Mobile) grün; test:unit 796 pass / 0 fail. Neu: tests/chat-title.test.mjs mit Verhaltens-Regression „erster Titelrequest schlägt fehl → nächster abgeschlossener Turn retryt“ plus Source-Level-Assertion, dass generateChatTitle() den Marker im Fehlerpfad setzt. (Die 4 Cancellations in chat-job-outcome.test.mjs sind vorbestehend, auch auf cleanem Checkout.)

Danke für die Hinweise – beide erledigt: **Retry-Fix (Merge-Blocker):** Der Retry-Vertrag ist jetzt in `public/js/chat/chat-title.js` ausgelagert (`needsTitleGeneration` / `markTitleRetry` / `clearTitleRetry`). `generateChatTitle()` setzt und persistiert `titleRetryPending` auf jedem nicht-finalisierenden Pfad (kein nutzbares Assistant, kein nutzbarer Input, **fehlgeschlagener Request/Catch**), und der Job-Completion-Gate nutzt `needsTitleGeneration()`. Damit wird der 502-Fehlerpfad nicht mehr still verschluckt: der nächste abgeschlossene substantielle Turn setzt den Titel erneut an. **Rebase:** Der Branch ist jetzt auf den aktuellen `main` (`4a5fe51`, gepatchter `nanoid`-Lock über PR #56) rebased – Commit `15c9491` (Titelmodus) + `ecc743a` (Retry-Fix) auf `4a5fe51`. Die PR übernimmt damit automatisch den gepatchten Lock. **Tests:** `lint`, `test:i18n`, `test:docs`, `test:ui` (Desktop+Mobile) grün; `test:unit` 796 pass / 0 fail. Neu: `tests/chat-title.test.mjs` mit Verhaltens-Regression „erster Titelrequest schlägt fehl → nächster abgeschlossener Turn retryt“ plus Source-Level-Assertion, dass `generateChatTitle()` den Marker im Fehlerpfad setzt. (Die 4 Cancellations in `chat-job-outcome.test.mjs` sind vorbestehend, auch auf cleanem Checkout.)
antonsxh deleted branch fix/issue-52-title-mode 2026-08-15 16:40:28 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
TLLX/CHAT-TLLX!55
No description provided.