Limit the length of AI-written smart playlist descriptions - #5458
Conversation
There was a problem hiding this comment.
Pull request overview
This PR prevents runaway AI engines from persisting excessively long smart playlist descriptions by enforcing a hard size cap (in UTF-8 bytes). When the AI response exceeds the cap, it is discarded so the playlist continues to use the normal rules summary as its description, avoiding oversized payloads in storage and in playlist listings sent to clients.
Changes:
- Introduces
MAX_AI_DESCRIPTION_BYTESand rejects AI-generated descriptions whose UTF-8 encoded size exceeds this limit. - Logs a debug message when an oversized AI description is discarded.
- Adds tests covering: oversized responses, boundary-at-cap acceptance, and multibyte/UTF-8 byte counting.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
music_assistant/providers/smart_playlist/__init__.py |
Enforces a UTF-8 byte-size cap on AI-generated smart playlist descriptions and falls back to rules summary when exceeded. |
tests/providers/smart_playlist/test_smart_playlist.py |
Adds unit tests validating oversized rejection, exact-cap acceptance, and byte-based measurement with multibyte characters. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (1)
music_assistant/providers/smart_playlist/init.py:1444
- [PROBLEM] _load_rules_from_disk coerces ai_description with str(...), which can turn corrupted/non-string JSON values into user-visible junk (and re-persist it); it also drops oversized descriptions only in-memory, leaving the oversized value on disk until some later flush. Prefer validating that the value is a string, and when you discard it, immediately rewrite the rules file (via _flush_rules_to_disk) so the oversized text is actually removed from disk.
# a description persisted before the size cap existed is dropped here too
description = str(entry.get("ai_description") or "")
if description and len(description.encode("utf-8")) <= MAX_AI_DESCRIPTION_BYTES:
self._descriptions_store[playlist_id] = description
8cfc001 to
30346e4
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (2)
music_assistant/providers/smart_playlist/init.py:1446
- [CRITICAL] _load_rules_from_disk() now encodes persisted ai_description to enforce the size cap, but description.encode("utf-8") can raise UnicodeEncodeError and abort the entire load (dropping even valid entries); catch encode errors and skip just the bad description.
description = entry.get("ai_description")
if (
isinstance(description, str)
and description
and len(description.encode("utf-8")) <= MAX_AI_DESCRIPTION_BYTES
music_assistant/providers/smart_playlist/init.py:1419
- [CRITICAL] Calling description.encode("utf-8") can raise UnicodeEncodeError for strings containing lone surrogates, which would crash AI refresh (and potentially the provider) instead of cleanly falling back to the rules summary; treat un-encodable text as an invalid AI response and return None.
This issue also appears on line 1442 of the same file.
description = response.strip()
if len(description.encode("utf-8")) > MAX_AI_DESCRIPTION_BYTES:
self.logger.debug(
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (2)
music_assistant/providers/smart_playlist/init.py:1447
- [PROBLEM]
_load_rules_from_diskalso encodes persisted descriptions to UTF-8 to enforce the byte cap; adding alen(description)check before encoding avoids allocating large temporary bytes objects when the stored value is already clearly over the cap by character count.
if (
isinstance(description, str)
and description
and len(description.encode("utf-8")) <= MAX_AI_DESCRIPTION_BYTES
):
music_assistant/providers/smart_playlist/init.py:1419
- [PROBLEM] The size check encodes the entire AI reply to UTF-8; for runaway responses this can allocate a large temporary bytes object and add avoidable CPU/memory overhead. Add a cheap
len(description)pre-check (which is always a lower bound for UTF-8 byte size) so oversized responses short-circuit without encoding.
This issue also appears on line 1443 of the same file.
description = response.strip()
if len(description.encode("utf-8")) > MAX_AI_DESCRIPTION_BYTES:
30346e4 to
02176f8
Compare
What does this implement/fix?
Smart Playlist can let an AI engine write the playlist description. That reply was used as-is, with no limit on how long it could be. A description is stored in the library database and on disk, and is sent to the apps with every playlist listing, so an AI engine that runs away and produces pages of text would leave that text sitting in the library instead of a short description.
The reply is now discarded when it is unreasonably long, and the normal rules summary is shown instead.
Related issue (if applicable):
Types of changes
bugfixnew-featureenhancementnew-providerbreaking-changerefactordocumentationmaintenancecidependenciesChanges
Checklist
pre-commit run --all-filespasses.pytestpasses, and tests have been added/updated undertests/where applicable.music-assistant/modelsis linked.music-assistant/frontendis linked.