Repository: ggerganov/whisper.cpp
File: src/whisper.cpp (C++)

Code before:
                            // Budget includes the prev token; we already consumed 1 slot.
                            int budget = max_ctx_half; // total allowed (including prev)

                            // Take as many static tokens as fit (reserving at least the prev token already placed)
                            int take_static = std::min(budget - 1, (int) prompt_past0.size());
                            if (take_static > 0) {
                                auto start0 = take_static < (int) prompt_past0.size() ? prompt_past0.end() - take_static : prompt_past0.begin();
                                prompt.insert(prompt.end(), start0, prompt_past0.end());
                            }

                            // Remaining budget for dynamic tail
                            int remaining = budget - take_static;
                            if (remaining > 0) {
                                int take_dynamic = std::min(remaining, (int) prompt_past1.size());
                                if (take_dynamic > 0) {
                                    prompt.insert(prompt.end(), prompt_past1.end() - take_dynamic, prompt_past1.end());
                                }
                            }
                        } else {
                            // Dynamic only path
                            int n_take = std::min(max_ctx_half, (int) prompt_past1.size());
                            if (n_take > 0) {
                                prompt.insert(prompt.end(), prompt_past1.end() - n_take, prompt_past1.end());
                            }
                        }
                    }
                }

                // init new transcription with sot, language (opt) and task tokens
                prompt.insert(prompt.end(), prompt_init.begin(), prompt_init.end());

                // print the prompt
                WHISPER_LOG_DEBUG("\n\n");
                for (int i = 0; i < (int) prompt.size(); i++) {
                    WHISPER_LOG_DEBUG("%s: prompt[%d] = %s\n", __func__, i, ctx->vocab.id_to_token.at(prompt[i]).c_str());
                }
                WHISPER_LOG_DEBUG("\n\n");

                // recreate the KV cache if the number of decoders has changed
                if (state->kv_self_n_dec < n_decoders_cur) {
                    WHISPER_LOG_DEBUG("%s: recreating KV cache: n_decoders_cur = %d\n", __func__, n_decoders_cur);

                    whisper_kv_cache_free(state->kv_self);

                    // overallocate to workaround KV cache fragmentation issues
                    const int factor = n_decoders_cur > 1 ? n_decoders_cur + 2 : 1;

                    if (!whisper_kv_cache_init(state->kv_self, state->backends[0], ctx->itype,
                                ctx->model.hparams.n_text_state,
                                ctx->model.hparams.n_text_layer,
                                GGML_PAD(ctx->model.hparams.n_text_ctx, 256)*factor)) {

Review comment (suggestion):
I think this part can become simpler:

```c++
if (params.n_max_text_ctx > 0 && t_cur < WHISPER_HISTORY_CONDITIONING_TEMP_CUTOFF) {
    const bool can_take0 = params.carry_initial_prompt && !prompt_past0.empty() && seek != seek_start;
    const bool can_take1 = !prompt_past1.empty();

    int max_ctx_half = std::min(params.n_max_text_ctx, whisper_n_text_ctx(ctx) / 2);
    if (max_ctx_half > 0 && (can_take0 || can_take1)) {
        prompt.push_back(whisper_token_prev(ctx));

        int n_take0 = 0;
        if (can_take0) {
            n_take0 = std::min<int>(max_ctx_half - 1, prompt_past0.size());
            if (n_take0 > 0) {
                auto start0 = n_take0 < (int)prompt_past0.size() ? prompt_past0.end() - n_take0 : prompt_past0.begin();
                prompt.insert(prompt.end(), start0, prompt_past0.end());
            }
        }

        int n_take1 = std::min<int>(max_ctx_half - n_take0 - 1, prompt_past1.size());
        if (n_take1 > 0) {
            prompt.insert(prompt.end(), prompt_past1.end() - n_take1, prompt_past1.end());
        }
    }
}
```

Code after:
                if (params.n_max_text_ctx > 0 && t_cur < WHISPER_HISTORY_CONDITIONING_TEMP_CUTOFF) {
                    const bool can_take0 = params.carry_initial_prompt && !prompt_past0.empty();
                    const bool can_take1 = !prompt_past1.empty();

                    if (max_prompt_ctx > 0 && (can_take0 || can_take1)) {
                        // Always start with previous token marker to connect continuity
                        prompt.push_back(whisper_token_prev(ctx));

                        // Take static tokens (initial prompt) first
                        int n_take0 = 0;
                        if (can_take0) {
                            n_take0 = prompt_past0.size();
                            prompt.insert(prompt.end(), prompt_past0.end() - n_take0, prompt_past0.end());
                        }

                        // Fill remaining budget with dynamic tokens (rolling context)
                        const int n_take1 = std::min<int>(max_prompt_ctx - n_take0 - 1, prompt_past1.size());
                        prompt.insert(prompt.end(), prompt_past1.end() - n_take1, prompt_past1.end());
                    }
                }

                // init new transcription with sot, language (opt) and task tokens
                prompt.insert(prompt.end(), prompt_init.begin(), prompt_init.end());

                // print the prompt
                WHISPER_LOG_DEBUG("\n\n");
                for (int i = 0; i < (int) prompt.size(); i++) {
                    WHISPER_LOG_DEBUG("%s: prompt[%d] = %s\n", __func__, i, ctx->vocab.id_to_token.at(prompt[i]).c_str());
                }
                WHISPER_LOG_DEBUG("\n\n");

                // recreate the KV cache if the number of decoders has changed
                if (state->kv_self_n_dec < n_decoders_cur) {
                    WHISPER_LOG_DEBUG("%s: recreating KV cache: n_decoders_cur = %d\n", __func__, n_decoders_cur);

                    whisper_kv_cache_free(state->kv_self);

                    // overallocate to workaround KV cache fragmentation issues
                    const int factor = n_decoders_cur > 1 ? n_decoders_cur + 2 : 1;

                    if (!whisper_kv_cache_init(state->kv_self, state->backends[0], ctx->itype,
                                ctx->model.hparams.n_text_state,
                                ctx->model.hparams.n_text_layer,
                                GGML_PAD(ctx->model.hparams.n_text_ctx, 256)*factor)) {
                        WHISPER_LOG_ERROR("%s: whisper_kv_cache_init() failed for self-attention cache\n", __func__);
                        whisper_free_state(state);
                        return -7;
                    }

                    state->kv_self_n_dec = n_decoders_cur;
                }