| 1267 | throw std::runtime_error("ACE-Step planner phase-1 decoder entered an invalid state"); |
| 1268 | } |
| 1269 | |
| 1270 | void observe_token(int32_t token) { |
| 1271 | switch (state_) { |
| 1272 | case Phase1State::ThinkTag: |
| 1273 | case Phase1State::NewlineAfterThink: |
| 1274 | case Phase1State::BpmName: |
| 1275 | case Phase1State::CaptionName: |
| 1276 | case Phase1State::DurationName: |
| 1277 | case Phase1State::KeyscaleName: |
| 1278 | case Phase1State::LanguageName: |
| 1279 | case Phase1State::TimesigName: |
| 1280 | consume_fixed_token(token); |
| 1281 | return; |
| 1282 | case Phase1State::EndOfTurn: |
| 1283 | if (token != config_.eos_token_id) { |
| 1284 | throw std::runtime_error("ACE-Step planner expected eos_token_id at end of turn"); |
| 1285 | } |
| 1286 | enter_state(Phase1State::Completed); |
| 1287 | return; |
| 1288 | case Phase1State::BpmValue: |
| 1289 | consume_value_token(token, Phase1State::CaptionName); |
| 1290 | return; |
| 1291 | case Phase1State::DurationValue: |
| 1292 | if (!duration_user_tokens_.empty()) { |
| 1293 | if (duration_user_position_ >= duration_user_tokens_.size() || |
| 1294 | duration_user_tokens_[duration_user_position_] != token) { |
| 1295 | throw std::runtime_error("ACE-Step planner duration token queue desynchronized"); |
| 1296 | } |
| 1297 | ++duration_user_position_; |
| 1298 | if (duration_user_position_ >= duration_user_tokens_.size()) { |
| 1299 | duration_user_tokens_.clear(); |
| 1300 | duration_user_position_ = 0; |
| 1301 | enter_state(Phase1State::KeyscaleName); |
| 1302 | } |
| 1303 | return; |
| 1304 | } |
| 1305 | consume_value_token(token, Phase1State::KeyscaleName); |
| 1306 | return; |
| 1307 | case Phase1State::KeyscaleValue: |
| 1308 | consume_value_token(token, Phase1State::LanguageName); |
| 1309 | return; |
| 1310 | case Phase1State::LanguageValue: |
| 1311 | consume_value_token(token, Phase1State::TimesigName); |
| 1312 | return; |
| 1313 | case Phase1State::TimesigValue: |
| 1314 | consume_value_token(token, Phase1State::EndOfTurn); |
| 1315 | return; |
| 1316 | case Phase1State::CaptionValue: { |
| 1317 | ++caption_token_count_; |
| 1318 | const std::string token_text = tokenizer_.decode({token}, false); |
| 1319 | caption_after_newline_ = token_text.find('\n') != std::string::npos; |
| 1320 | if (caption_ending_) { |
| 1321 | pending_field_name_ += token_text; |
| 1322 | if (token_text.find(':') != std::string::npos || trim_ascii(token_text) == ":") { |
| 1323 | const std::string field_name = normalize_field_name(pending_field_name_); |
| 1324 | caption_ending_ = false; |
| 1325 | pending_field_name_.clear(); |
| 1326 | if (field_name == "duration") { |