Commit 184f65360 for llama.cpp

commit 184f6536024668e8908ab8c86033d56708e62b40
Author: pzhu <q1091803103@gmail.com>
Date:   Fri Oct 23 06:38:03 2026 +0800

    server: Substitute rerank placeholder from the original template only. (#30864)

diff --git a/tests/test-server-component.cpp b/tests/test-server-component.cpp
index aa353e190..18e0cdc2f 100644
--- a/tests/test-server-component.cpp
+++ b/tests/test-server-component.cpp
@@ -435,6 +435,35 @@ static void test_decision_escape(testing & t) {
     });
 }

+static void test_rerank_template(testing & t) {
+    struct test_case {
+        const char * name;
+        std::string tmpl;
+        std::string query;
+        std::string doc;
+        std::string expected;
+    };
+    const test_case cases[] = {
+        {"plain inputs", "Q: {query}\nD: {document}", "query", "doc", "Q: query\nD: doc"},
+        {"document placeholder in query", "Q: {query}\nD: {document}", "Explain {document}.", "doc", "Q: Explain {document}.\nD: doc"},
+        {"query placeholder in query", "{query}|{document}", "{query}", "doc", "{query}|doc"},
+        {"placeholders in both inputs", "{query}|{document}", "{query} {document}", "{query} {document}", "{query} {document}|{query} {document}"},
+        {"repeated placeholders", "{query}|{document}|{query}|{document}", "{document}", "doc", "{document}|doc|{document}|doc"},
+        {"adjacent reversed placeholders", "{document}{query}", "query", "doc", "docquery"},
+        {"query only", "{query}", "{document}", "doc", "{document}"},
+        {"document only", "{document}", "query", "{query}", "{query}"},
+        {"no placeholders", "fixed", "{document}", "{query}", "fixed"},
+        {"unknown and incomplete placeholders", "{unknown}|{query}|{document}|{query", "query", "doc", "{unknown}|query|doc|{query"},
+        {"nested braces", "{{query}}|{{document}}", "query", "doc", "{query}|{doc}"},
+        {"placeholder formed at boundary", "{query}ument}", "{doc", "doc", "{document}"},
+        {"empty inputs", "Q: {query}\nD: {document}", "", "", "Q: \nD: "},
+        {"empty template", "", "query", "doc", ""},
+    };
+    for (const auto & test : cases) {
+        t.assert_equal(test.name, test.expected, format_rerank_template(test.tmpl, test.query, test.doc));
+    }
+}
+
 int main(int argc, char ** argv) {
     testing t;

@@ -454,6 +483,7 @@ int main(int argc, char ** argv) {
     t.test("lora_helpers",  test_lora_helpers);
     t.test("server_pipe",   test_server_pipe);
     t.test("decision_escape", test_decision_escape);
+    t.test("rerank_template", test_rerank_template);

     return t.summary();
 }
diff --git a/tools/server/server-common.cpp b/tools/server/server-common.cpp
index 4f1acba1a..10e04d370 100644
--- a/tools/server/server-common.cpp
+++ b/tools/server/server-common.cpp
@@ -1945,6 +1945,26 @@ llama_tokens format_prompt_infill(
     return embd_inp;
 }

+std::string format_rerank_template(
+        const std::string & tmpl,
+        const std::string & query,
+        const std::string & doc) {
+    std::string prompt;
+    prompt.reserve(tmpl.size());
+    for (size_t pos = 0; pos < tmpl.size();) {
+        if (tmpl.compare(pos, 7, "{query}") == 0) {
+            prompt += query;
+            pos += 7;
+        } else if (tmpl.compare(pos, 10, "{document}") == 0) {
+            prompt += doc;
+            pos += 10;
+        } else {
+            prompt += tmpl[pos++];
+        }
+    }
+    return prompt;
+}
+
 server_tokens format_prompt_rerank(
         const struct llama_model * model,
         const struct llama_vocab * vocab,
@@ -1974,9 +1994,7 @@ server_tokens format_prompt_rerank(
             d += get_media_marker();
         }

-        std::string prompt = rerank_prompt;
-        string_replace_all(prompt, "{query}"   , q);
-        string_replace_all(prompt, "{document}", d  );
+        std::string prompt = format_rerank_template(rerank_prompt, q, d);

         if (query_files.empty() && doc_files.empty()) {
             server_tokens tokens = tokenize_input_subprompt(vocab, mctx, prompt, false, true, init_opt);
diff --git a/tools/server/server-common.h b/tools/server/server-common.h
index 8bbff7726..09ffa9a56 100644
--- a/tools/server/server-common.h
+++ b/tools/server/server-common.h
@@ -592,6 +592,11 @@ llama_tokens format_prompt_infill(
         const bool spm_infill,
         const llama_tokens & tokens_prompt);

+std::string format_rerank_template(
+        const std::string & tmpl,
+        const std::string & query,
+        const std::string & doc);
+
 // format rerank task: [BOS]query[EOS][SEP]doc[EOS].
 // query_files/doc_files carry decoded media for multimodal (Qwen) inputs; when non-empty the
 // prompt is built with get_media_marker() sentinels and spliced via process_mtmd_prompt.