Conversation
Byte-wise title[:47] split multi-byte Chinese runes, so ListConversations could not marshal existing sessions.
nishantmonu51
left a comment
There was a problem hiding this comment.
The rune-safe cut in promptToTitle and the strings.ToValidUTF8 sanitization in sessionToPB cover every path that serves a stored title: sessionToPB is the only constructor of runtimev1.Conversation, so ListConversations, GetConversation, and the forked title built in runtime/ai/ai.go:226 all go through it. The four new tests pin both the truncation boundary and the marshal boundary.
Worth stating explicitly: rows already stored with invalid UTF-8 are repaired only at the marshal boundary, not in the catalog, so the U+FFFD stays in those titles until they are renamed. That reads as the right trade-off given the blast radius.
|
|
||
| // truncateUTF8 shortens s to at most maxBytes, appending "..." when truncated. | ||
| // The cut is always on a UTF-8 rune boundary so the result stays valid UTF-8. | ||
| func truncateUTF8(s string, maxBytes int) string { |
There was a problem hiding this comment.
truncateUTF8 is called exactly once, with a constant, which also makes the maxBytes <= len(ellipsis) branch unreachable. Per the repo's convention against single-use utility functions, the back-off could be inlined in promptToTitle as a walk from index 47 while !utf8.RuneStart(title[i]), which avoids re-validating the whole prefix on every iteration. Either form relies on the prompt being valid UTF-8 on entry, which holds for all current entry points.
ListConversationsfailed to marshal when a stored conversation title contained invalid UTF-8.promptToTitletruncated with a byte slice (title[:47]), which split multi-byte runes.strings.ToValidUTF8at the marshal boundary (invalid bytes become U+FFFD) so previously stored rows still list.Checklist:
Developed in collaboration with Claude Code