Repository navigation
Collapse invalid UTF-8 runs into a single U+FFFD on decode - #28
Open
mertyildiran wants to merge 1 commit into
Open
mertyildiran wants to merge 1 commit into
mertyildiran wants to merge 1 commit into
Conversation
Matches tiktoken's errors="replace". Previously Decode could return invalid UTF-8 when a token splits a multi-byte character, and re-encoding it doubled the replacement characters.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #27
Problem
Decodecan return a string that is not valid UTF-8, and feeding that string back toEncodedoes not round-trip — the text comes back changed.Byte-level BPE tokens are allowed to split a multi-byte character, so the concatenation of decoded token bytes can end mid-sequence. In
o200k_base, token35895is"\xe8\x96"— the first two bytes of a 3-byte character.When that string was passed to
Encode,regexp2converted it to UTF-16 internally and substitutedU+FFFDfor each invalid byte, so a 2-byte truncated sequence produced two replacement characters instead of one.Reference behavior
Python's tiktoken decodes with
decode_bytes(...).decode("utf-8", errors="replace"), which collapses each run of invalid bytes into a singleU+FFFD:Fix
Codec.Decodenow returnsstrings.ToValidUTF8(out, "\uFFFD")— one replacement character per invalid run, matchingerrors="replace".Decode(ids)"...()*\xe8\x96 ред""...()*� ред""...()*� ред"Encodeof that[..., 10123, ...]("��")[..., 3251, ...]("�")[..., 3251, ...]Decodeagain"...()*�� ред"— changed"...()*� ред"— stable"...()*� ред"The ids themselves are not preserved (
35895→3251). That is inherent to re-encoding sanitized text and matches tiktoken exactly; only the text round-trips.Behavior change to note
Decodewill no longer return invalid UTF-8. Anyone relying on the raw bytes for byte-level work would now get replacement characters. I believe this is the right default since it matches tiktoken, but it is observable — happy to discuss alternatives (e.g. an opt-inDecodeBytesalongside the current behavior) if you prefer.Test
Added
TestO200kBaseDecodeInvalidUTF8, which decodes token35895, encodes the result, and decodes again. It fails on the current code with10123and the doubled replacement characters.