| 1068 | /* Streaming cannot emit the last max_stop_len-1 bytes yet: a stop sequence |
| 1069 | * may start there and finish in the next token. The final flush releases |
| 1070 | * this small tail once generation ends without a stop hit. */ |
| 1071 | if (!stops->len || stops->max_len <= 1) return text_len; |
| 1072 | const size_t hold = stops->max_len - 1; |
| 1073 | return text_len > hold ? text_len - hold : 0; |
| 1074 | } |
| 1075 | |
| 1076 | static int utf8_expected_len(unsigned char c) { |
| 1077 | if (c < 0x80) return 1; |
| 1078 | if (c >= 0xc2 && c <= 0xdf) return 2; |
| 1079 | if (c >= 0xe0 && c <= 0xef) return 3; |
| 1080 | if (c >= 0xf0 && c <= 0xf4) return 4; |
| 1081 | return 1; |
| 1082 | } |
| 1083 | |
| 1084 | /* Tokenizers can split a multi-byte UTF-8 character across two tokens. If an |
| 1085 | * SSE delta ends at that boundary, some clients replace the incomplete byte |
| 1086 | * sequence with U+FFFD and later send the corrupted text back, destroying KV |
| 1087 | * cache prefix matches. Hold only the trailing incomplete character; the next |
| 1088 | * generated token will complete it. */ |
| 1089 | static size_t utf8_stream_safe_len(const char *s, size_t start, |
| 1090 | size_t limit, bool final) { |
| 1091 | if (final || !s || limit <= start) return limit; |
| 1092 | |
| 1093 | size_t p = limit; |
| 1094 | int cont = 0; |
| 1095 | while (p > start && cont < 4 && |
| 1096 | (((unsigned char)s[p - 1] & 0xc0) == 0x80)) |
| 1097 | { |
| 1098 | p--; |
| 1099 | cont++; |
| 1100 | } |
| 1101 | |
| 1102 | if (p == limit) { |
| 1103 | return utf8_expected_len((unsigned char)s[limit - 1]) > 1 ? |
| 1104 | limit - 1 : limit; |
| 1105 | } |
| 1106 | if (p == start && (((unsigned char)s[p] & 0xc0) == 0x80)) return start; |
| 1107 | |
| 1108 | size_t lead = p - 1; |
| 1109 | int need = utf8_expected_len((unsigned char)s[lead]); |
| 1110 | return (limit - lead) < (size_t)need ? lead : limit; |
| 1111 | } |
| 1112 | |
| 1113 | static bool parse_stream_options(const char **p, bool *include_usage) { |
| 1114 | json_ws(p); |
| 1115 | if (**p != '{') return json_skip_value(p); |
| 1116 | (*p)++; |
| 1117 | json_ws(p); |
| 1118 | while (**p && **p != '}') { |
| 1119 | char *key = NULL; |
no test coverage detected