feat(queue): Gesetze max_text und max_age — gekürzte Langtexte, verfallene Stau-Ansagen
Zwei Löcher im Anti-Spam-Gesetz, die ein Prompt trivial nutzt: Ein Agent
kann 64 KB Text einreichen (ElevenLabs stellt die Rechnung, die Ansage
dauert Minuten), und geparkte normal-Ansagen spielen unbegrenzt spät —
„Build fertig" zweieinhalb Minuten nach dem Build ist keine Nachricht.
- queue.max_text (Default 400 Zeichen, Env TALK_MAX_TEXT): längere Texte
werden beim Eintritt an einer Wortgrenze gekürzt und so gesprochen; die
/speak-Antwort meldet truncated, die CLI warnt auf stderr, das MCP-
Ergebnis sagt es im Text. Runen, nicht Bytes.
- queue.max_age (Default 2m, Env TALK_MAX_AGE): Items, die beim
Fälligwerden länger gewartet haben, werden verworfen (discarded
"expired", Protokoll nennt Wartezeit und Grenze). now:true ist
ausgenommen. Rang: now > veraltet > Ruhezeit > Rate-Limit.
- /status trägt "limits": {max_text, max_age}; `talk status` zeigt sie.
- Negative Werte sind Config-Fehler; 0 = unbegrenzt.
Tests: truncateText-Tabelle (Wortgrenze, Satzzeichen, Runen), Enqueue-
Kürzung, decide-Vorrang inkl. now-Ausnahme, geparktes Item verfällt;
Config-Schichten; Prozessgrenze: Provider bekommt die gekürzte Fassung,
dritte von drei Stau-Ansagen wird nie gesprochen.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
79314dfb0f
commit
97650ad0ec
13 files changed
+430
-26
No files matched your search
@@ -65,9 +65,9 @@ schreibt die Mute-Datei direkt.
|
||||
|
||||
| Endpunkt | Wirkung |
|
||||
| --- | --- |
|
||||
| `POST /speak` | `{text, priority?, provider?, voice?, lang?, now?}` → `202 {"id":"…"}`; bei Mute: `202 {"id":"","muted":true}`; bei Gesetz-Verwurf: `202 {"id":"","discarded":"rate_limit"\|"quiet_hours"}` (+ `"toast":true` im Toast-Modus) — verworfen, dokumentiertes Verhalten |
|
||||
| `POST /speak` | `{text, priority?, provider?, voice?, lang?, now?}` → `202 {"id":"…"}` (+ `"truncated":true`, wenn auf `max_text` gekürzt); bei Mute: `202 {"id":"","muted":true}`; bei Gesetz-Verwurf: `202 {"id":"","discarded":"rate_limit"\|"quiet_hours"}` (+ `"toast":true` im Toast-Modus) — verworfen, dokumentiertes Verhalten |
|
||||
| `OPTIONS /speak` | CORS-Preflight → `204` mit Freigabe-Headern, wenn die `Origin` in `server.allowed_origins` steht (siehe unten); sonst `204` ohne CORS-Header |
|
||||
| `GET /status` | `{"version", "queue", "queue_ids", "current", "muted", "provider", "rate_limit": {"interval", "allow_high_burst", "next_slot"}, "quiet_hours": {"window", "active", "mode", "until"}, "mcp": true, "cors": [origins]}` |
|
||||
| `GET /status` | `{"version", "queue", "queue_ids", "current", "muted", "provider", "rate_limit": {"interval", "allow_high_burst", "next_slot"}, "quiet_hours": {"window", "active", "mode", "until"}, "limits": {"max_text", "max_age"}, "mcp": true, "cors": [origins]}` |
|
||||
| `POST /cancel` | bricht die laufende Ansage ab + leert die Queue → `200 {"cancelled":n}` |
|
||||
| `POST /mute` / `POST /unmute` | persistenter Mute-State → `200 {"muted":bool}` |
|
||||
| `POST /shutdown` | fährt den Daemon herunter (`talk daemon stop`) → `200 {"ok":true}` |
|
||||
@@ -117,21 +117,38 @@ sind Opt-in wie Mute). In der Ruhezeit verfällt Audio, auch für high
|
||||
Notification-Anbindung).
|
||||
- `now:true` **bricht auch die Ruhezeit** (bewusster Ausbruch).
|
||||
|
||||
**Rangordnung:** manuelles Mute gewinnt immer > `now` > Ruhezeit >
|
||||
Rate-Limit. Konfiguration (config.toml, Env schlägt Datei):
|
||||
**Länge und Alter:** Zwei weitere Gesetze gegen das, was Prompts gern tun
|
||||
— die Langantwort vorlesen und Ansagen stapeln:
|
||||
|
||||
- `max_text` (Default **400 Zeichen**, etwa zwei bis drei Sätze): Längere
|
||||
Texte werden beim Eintritt an einer Wortgrenze **gekürzt** und so
|
||||
gesprochen; die Antwort meldet `"truncated": true`, die CLI warnt auf
|
||||
stderr, das MCP-Ergebnis sagt es im Text. Der Nutzer hört den Anfang
|
||||
statt zehn Minuten Vortrag, das API-Budget bleibt begrenzt.
|
||||
- `max_age` (Default **2 Minuten**): Was länger in der Queue parkt (Rate-
|
||||
Limit, Stau), ist keine Nachricht mehr und wird beim Fälligwerden
|
||||
**verworfen** (`discarded: "expired"` im Protokoll; die 202-Antwort beim
|
||||
Eintritt bleibt eine Zusage, denn beim Eintritt ist nichts veraltet).
|
||||
`now:true` wartet nie lange und ist ausgenommen.
|
||||
|
||||
**Rangordnung:** manuelles Mute gewinnt immer > `now` > veraltet (`max_age`)
|
||||
> Ruhezeit > Rate-Limit; `max_text` greift beim Eintritt auf alles.
|
||||
Konfiguration (config.toml, Env schlägt Datei):
|
||||
|
||||
```toml
|
||||
[queue]
|
||||
rate_limit = "30s" # Dauer; "0s" = unbegrenzt (TALK_RATE_LIMIT)
|
||||
allow_high_burst = true # high darf verstoßen (TALK_ALLOW_HIGH_BURST)
|
||||
max_text = 400 # Zeichen; 0 = unbegrenzt (TALK_MAX_TEXT)
|
||||
max_age = "2m" # Wartezeit; "0s" = unbegrenzt (TALK_MAX_AGE)
|
||||
|
||||
quiet_hours = "18:00-08:00" # leer = aus; Env TALK_QUIET_HOURS ("off" = aus)
|
||||
quiet_mode = "discard" # discard | toast (TALK_QUIET_MODE)
|
||||
```
|
||||
|
||||
`talk status` zeigt den Gesetz-State: `rate-limit: 30s (high-burst
|
||||
erlaubt), nächster slot …` und `ruhezeit: 18:00-08:00 (modus discard,
|
||||
aktiv bis 08:00)`.
|
||||
erlaubt), nächster slot …`, `ruhezeit: 18:00-08:00 (modus discard,
|
||||
aktiv bis 08:00)` und `limits: max. 400 Zeichen, max. Wartezeit 2m0s`.
|
||||
|
||||
### CORS-Tür + MCP-Endpoint (Task 06)
|
||||
|
||||
|
||||
Reference in new issue
Block a user