Commit 6776688
authored
fix: place Gemma 4 server <|audio|> block inside the user turn (#440)
* fix: place Gemma 4 server <|audio|> block inside the user turn
Gemma 4 audio understanding over the server (POST /v1/chat/completions with an input_audio part) emitted 0 tokens. The server renders chat messages text-only (MessageContent::text() drops input_audio content parts), so the chat template never produced an <|audio|> marker; expand_gemma4_audio_tokens_for_server then found no placeholder and used its "insert before the final token" fallback, which lands the BOA + AUDIO*N + EOA block inside the trailing model turn of the Gemma generation prompt and forces an immediate EOS. This is the server half of the placement defect that #436 fixed for the CLI.
expand_gemma4_audio_tokens_for_server now places the audio block at the token-stream level, the same layer the image path uses via expand_gemma4_image_tokens / apply_image_token_blocks, so the prefix-cache-sensitive render path in chat_request.rs is untouched. When a rendered <|audio|> placeholder is present it is wrapped in place; otherwise the block is spliced in immediately before the last <end_of_turn> token, which closes the latest user turn in a Gemma generation prompt, so the audio stays inside the user turn. The model worker resolves the <end_of_turn> id from the tokenizer and threads it through both Gemma 4 audio paths: prepare_gemma4_audio_embeddings (Conformer VLM) and prepare_gemma4_unified_audio_embeddings (encoder-free Unified). The legacy before-the-final-token insertion stays only as a last resort for prompts with no <end_of_turn> marker.
Non-audio requests are byte-identical: only the two audio embedding paths change and chat_request.rs is not touched, so text-only, image-only, and non-Gemma server requests keep their exact prompt and prompt-cache prefix behavior. New unit tests cover in-place wrap, user-turn insertion, multi-turn last-user-turn targeting, and both last-resort fallbacks.
* fix(server): resolve Gemma 4 end-of-turn token so audio lands in the user turn
The server places the Gemma 4 audio block before the last end-of-turn token (issue #437), but `resolve_end_of_turn_token_id` only looked up "<end_of_turn>". Gemma 4 renamed the marker to "<turn|>" (id 106; start-of-turn is "<|turn>"), so the lookup returned None and the placement silently degraded to the model-turn fallback, still yielding 0 tokens. Try both "<end_of_turn>" (Gemma 2/3) and "<turn|>" (Gemma 4) so the audio block lands inside the last user turn. Verified end to end: a chat-completions request with an input_audio part to gemma-4-e2b now transcribes (0 -> 120 tokens) instead of emitting EOS at prefill.
* test: add regression tests for resolve_end_of_turn_token_id
Add three unit tests to src/server/model_worker_tests.rs covering the function that had the bug (resolve_end_of_turn_token_id had no tests before this PR):
- resolve_end_of_turn_id_handles_gemma4_turn_marker: a tokenizer with "<turn|>" = id 106 but no "<end_of_turn>" must return Some(106). This is the exact regression guard for the #437 bug, where the old implementation only looked up "<end_of_turn>" and returned None for Gemma 4 tokenizers.
- resolve_end_of_turn_id_handles_gemma23_end_of_turn_marker: a tokenizer with "<end_of_turn>" = id 107 must return Some(107).
- resolve_end_of_turn_id_returns_none_when_no_marker_present: a tokenizer with neither marker must return None so the caller keeps its own fallback.
Each test builds a minimal HuggingFace BPE stub (via two helper functions, stub_eot_tokenizer and stub_tokenizer_no_eot) that mirrors the pattern of MlxcelTokenizer::stub_with_byte_fallback.
Also remove the stale "not yet wired through the chat prompt" note from docs/supported-models.md and replace it with a brief description of what the fix delivers.1 parent 263a759 commit 6776688
5 files changed
Lines changed: 326 additions & 31 deletions
File tree
- docs
- src
- multimodal
- server
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
74 | | - | |
| 74 | + | |
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1089 | 1089 | | |
1090 | 1090 | | |
1091 | 1091 | | |
1092 | | - | |
| 1092 | + | |
| 1093 | + | |
1093 | 1094 | | |
1094 | | - | |
1095 | | - | |
| 1095 | + | |
| 1096 | + | |
| 1097 | + | |
| 1098 | + | |
| 1099 | + | |
| 1100 | + | |
| 1101 | + | |
| 1102 | + | |
| 1103 | + | |
| 1104 | + | |
| 1105 | + | |
| 1106 | + | |
| 1107 | + | |
| 1108 | + | |
| 1109 | + | |
| 1110 | + | |
| 1111 | + | |
| 1112 | + | |
| 1113 | + | |
| 1114 | + | |
| 1115 | + | |
| 1116 | + | |
1096 | 1117 | | |
1097 | 1118 | | |
1098 | 1119 | | |
1099 | 1120 | | |
1100 | 1121 | | |
1101 | 1122 | | |
| 1123 | + | |
1102 | 1124 | | |
1103 | | - | |
1104 | | - | |
1105 | | - | |
1106 | | - | |
1107 | | - | |
1108 | | - | |
1109 | | - | |
1110 | | - | |
1111 | | - | |
1112 | | - | |
| 1125 | + | |
| 1126 | + | |
| 1127 | + | |
| 1128 | + | |
| 1129 | + | |
| 1130 | + | |
| 1131 | + | |
| 1132 | + | |
| 1133 | + | |
| 1134 | + | |
| 1135 | + | |
| 1136 | + | |
| 1137 | + | |
| 1138 | + | |
| 1139 | + | |
| 1140 | + | |
| 1141 | + | |
| 1142 | + | |
| 1143 | + | |
1113 | 1144 | | |
| 1145 | + | |
| 1146 | + | |
1114 | 1147 | | |
1115 | | - | |
1116 | | - | |
1117 | | - | |
1118 | | - | |
1119 | | - | |
1120 | | - | |
1121 | | - | |
1122 | | - | |
1123 | | - | |
| 1148 | + | |
| 1149 | + | |
| 1150 | + | |
| 1151 | + | |
| 1152 | + | |
| 1153 | + | |
| 1154 | + | |
| 1155 | + | |
| 1156 | + | |
| 1157 | + | |
| 1158 | + | |
| 1159 | + | |
| 1160 | + | |
| 1161 | + | |
1124 | 1162 | | |
1125 | | - | |
1126 | 1163 | | |
1127 | 1164 | | |
1128 | 1165 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
221 | 222 | | |
222 | 223 | | |
223 | 224 | | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
957 | 957 | | |
958 | 958 | | |
959 | 959 | | |
960 | | - | |
961 | | - | |
962 | | - | |
| 960 | + | |
| 961 | + | |
| 962 | + | |
| 963 | + | |
| 964 | + | |
| 965 | + | |
| 966 | + | |
| 967 | + | |
| 968 | + | |
| 969 | + | |
| 970 | + | |
| 971 | + | |
| 972 | + | |
963 | 973 | | |
964 | 974 | | |
965 | | - | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
966 | 982 | | |
967 | 983 | | |
968 | 984 | | |
| |||
1045 | 1061 | | |
1046 | 1062 | | |
1047 | 1063 | | |
| 1064 | + | |
| 1065 | + | |
| 1066 | + | |
| 1067 | + | |
| 1068 | + | |
| 1069 | + | |
| 1070 | + | |
| 1071 | + | |
| 1072 | + | |
| 1073 | + | |
| 1074 | + | |
| 1075 | + | |
| 1076 | + | |
| 1077 | + | |
| 1078 | + | |
| 1079 | + | |
| 1080 | + | |
| 1081 | + | |
| 1082 | + | |
| 1083 | + | |
| 1084 | + | |
| 1085 | + | |
| 1086 | + | |
| 1087 | + | |
| 1088 | + | |
| 1089 | + | |
| 1090 | + | |
| 1091 | + | |
| 1092 | + | |
| 1093 | + | |
| 1094 | + | |
| 1095 | + | |
| 1096 | + | |
| 1097 | + | |
| 1098 | + | |
| 1099 | + | |
1048 | 1100 | | |
1049 | 1101 | | |
1050 | 1102 | | |
| |||
1053 | 1105 | | |
1054 | 1106 | | |
1055 | 1107 | | |
| 1108 | + | |
1056 | 1109 | | |
1057 | 1110 | | |
1058 | 1111 | | |
| |||
1087 | 1140 | | |
1088 | 1141 | | |
1089 | 1142 | | |
1090 | | - | |
| 1143 | + | |
| 1144 | + | |
1091 | 1145 | | |
1092 | 1146 | | |
1093 | 1147 | | |
1094 | 1148 | | |
1095 | 1149 | | |
1096 | 1150 | | |
| 1151 | + | |
1097 | 1152 | | |
1098 | 1153 | | |
1099 | 1154 | | |
| |||
1163 | 1218 | | |
1164 | 1219 | | |
1165 | 1220 | | |
| 1221 | + | |
1166 | 1222 | | |
1167 | 1223 | | |
1168 | 1224 | | |
| |||
1201 | 1257 | | |
1202 | 1258 | | |
1203 | 1259 | | |
| 1260 | + | |
1204 | 1261 | | |
1205 | 1262 | | |
1206 | 1263 | | |
| |||
0 commit comments