| 1390 | memset(chat, 0, sizeof(*chat)); |
| 1391 | ds4_chat_begin(engine, &chat->transcript); |
| 1392 | chat->think_prefix_pos = chat->transcript.len; |
| 1393 | repl_chat_apply_think_prefix(engine, chat, cli_effective_think_mode(&cfg->gen)); |
| 1394 | if (cfg->gen.system && cfg->gen.system[0]) { |
| 1395 | ds4_chat_append_message(engine, &chat->transcript, "system", cfg->gen.system); |
| 1396 | } |
| 1397 | return repl_chat_create_session(engine, chat, cfg->gen.ctx_size); |
| 1398 | } |
| 1399 | |
| 1400 | static void repl_chat_free(repl_chat *chat) { |
| 1401 | if (!chat) return; |
| 1402 | ds4_session_free(chat->session); |
| 1403 | ds4_tokens_free(&chat->transcript); |
| 1404 | memset(chat, 0, sizeof(*chat)); |
| 1405 | } |
| 1406 | |
| 1407 | static int repl_chat_set_ctx(ds4_engine *engine, repl_chat *chat, int ctx_size) { |
| 1408 | ds4_session_free(chat->session); |
| 1409 | chat->session = NULL; |
| 1410 | chat->ctx_size = 0; |
| 1411 | return repl_chat_create_session(engine, chat, ctx_size); |
| 1412 | } |
| 1413 | |
| 1414 | static bool repl_chat_assistant_turn_uses_eos(ds4_engine *engine) { |
| 1415 | return !ds4_engine_is_glm_dsa(engine); |
| 1416 | } |
| 1417 | |
| 1418 | /* Run one interactive turn. The transcript is tentatively extended with user |
| 1419 | * and assistant markers, then ds4_session_sync() decides whether this is a KV |
| 1420 | * continuation. If prompt processing fails, the transcript rolls back before |
| 1421 | * returning to the prompt. */ |
| 1422 | static int run_chat_turn(ds4_engine *engine, cli_config *cfg, repl_chat *chat, const char *user_text) { |
| 1423 | if (!chat->session) { |
| 1424 | fprintf(stderr, "ds4: no active interactive KV cache\n"); |
| 1425 | return 1; |
| 1426 | } |
| 1427 | |
| 1428 | ds4_think_mode think_mode = ds4_think_mode_for_context(cfg->gen.think_mode, |
| 1429 | chat->ctx_size); |
| 1430 | repl_chat_apply_think_prefix(engine, chat, think_mode); |
| 1431 | const int rollback_len = chat->transcript.len; |
| 1432 | ds4_chat_append_message(engine, &chat->transcript, "user", user_text); |
| 1433 | ds4_chat_append_assistant_prefix(engine, &chat->transcript, think_mode); |
| 1434 | |
| 1435 | const int old_pos = ds4_session_pos(chat->session); |
| 1436 | const int common = ds4_session_common_prefix(chat->session, &chat->transcript); |
| 1437 | const int cached = common == old_pos && chat->transcript.len >= old_pos ? common : 0; |
| 1438 | const int suffix = chat->transcript.len - cached; |
| 1439 | |
| 1440 | char err[160]; |
| 1441 | cli_prefill_progress progress = { |
| 1442 | .base_tokens = cached, |
| 1443 | .input_tokens = suffix, |
| 1444 | .use_color = ds4_log_is_tty(stderr), |
| 1445 | }; |
| 1446 | const double t_prefill0 = cli_now_sec(); |
| 1447 | ds4_session_set_progress(chat->session, cli_prefill_progress_cb, &progress); |
| 1448 | ds4_session_set_display_progress(chat->session, |
| 1449 | progress.use_color ? cli_prefill_progress_cb : NULL, |
no test coverage detected