From e44fcd997ec5dae90f26666a1033a46e649a97fd Mon Sep 17 00:00:00 2001 From: Jenny Ferries Date: Wed, 26 Aug 2026 17:08:55 -0700 Subject: [PATCH] Use tokenizer options for chat template kwargs Route typed chat template kwargs through the existing tokenizer UpdateOptions API, remove the unreleased parallel GenAI API surface, update coverage, and pin the merged Extensions implementation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3783556e-822f-4790-a42b-faee9fb57e6b --- cmake/deps.txt | 2 +- src/models/model.cpp | 16 ---------------- src/models/model.h | 2 -- src/ort_genai.h | 8 -------- src/ort_genai_c.cpp | 11 ----------- src/ort_genai_c.h | 19 +++++-------------- test/c_api_tests.cpp | 24 +++++++++++++++++------- 7 files changed, 23 insertions(+), 59 deletions(-) diff --git a/cmake/deps.txt b/cmake/deps.txt index 3617c92470..2f84e5a925 100644 --- a/cmake/deps.txt +++ b/cmake/deps.txt @@ -14,7 +14,7 @@ pybind11;https://github.com/pybind/pybind11/archive/refs/tags/v2.13.6.zip;f78029 googletest;https://github.com/google/googletest/archive/530d5c8c84abd2a46f38583ee817743c9b3a42b4.zip;5e3a61db2aa975cfd0f97ba92c818744e7fa7034 microsoft_wil;https://github.com/microsoft/wil/archive/refs/tags/v1.0.230629.1.zip;e4a542a323c070376f7c2d1973d0f7ddbc1d2fa5 directx_headers;https://github.com/microsoft/DirectX-Headers/archive/refs/tags/v1.613.1.zip;47653509a3371eabb156360f42faf582f314bf2e -onnxruntime_extensions;https://github.com/microsoft/onnxruntime-extensions.git;bd0e21c11187e0b8a2385d1c61122a4d259a53a0 +onnxruntime_extensions;https://github.com/microsoft/onnxruntime-extensions.git;7192ff774619fb37358783714ec996a438bfdb05 # These two dependencies are for the optional constrained decoding feature (USE_GUIDANCE) llguidance;https://github.com/microsoft/llguidance.git;94fa39128ef184ffeda33845f6d333f332a34b4d diff --git a/src/models/model.cpp b/src/models/model.cpp index 7f222f6aa7..acc506640b 100644 --- a/src/models/model.cpp +++ b/src/models/model.cpp @@ -431,22 +431,6 @@ std::string Tokenizer::ApplyChatTemplate(const char* template_str, const char* m return text_ptr; } -std::string Tokenizer::ApplyChatTemplateWithOptions(const char* template_str, const char* messages, const char* tools, - const char* template_kwargs, bool add_generation_prompt) const { - ort_extensions::OrtxObjectPtr templated_text; - CheckResult(OrtxApplyChatTemplateWithOptions(tokenizer_, template_str, messages, tools, template_kwargs, - templated_text.ToBeAssigned(), add_generation_prompt, - false /*tokenize*/)); - - ort_extensions::OrtxObjectPtr tensor; - CheckResult(OrtxTensorResultGetAt(templated_text.get(), 0, tensor.ToBeAssigned())); - - const char* text_ptr{}; - CheckResult(OrtxGetTensorData(tensor.get(), reinterpret_cast(&text_ptr), nullptr, nullptr)); - - return text_ptr; -} - std::vector Tokenizer::EncodeBatch(std::span strings) const { std::vector> sequences; std::vector> span_sequences; diff --git a/src/models/model.h b/src/models/model.h index c44f8a3bce..b0edc8c711 100644 --- a/src/models/model.h +++ b/src/models/model.h @@ -133,8 +133,6 @@ struct Tokenizer : std::enable_shared_from_this, LeakChecked Encode(const char* text) const; std::string Decode(std::span tokens) const; std::string ApplyChatTemplate(const char* template_str, const char* messages, const char* tools, bool add_generation_prompt) const; - std::string ApplyChatTemplateWithOptions(const char* template_str, const char* messages, const char* tools, - const char* template_kwargs, bool add_generation_prompt) const; std::vector EncodeBatch(std::span strings) const; std::shared_ptr EncodeBatch(std::span strings) const; diff --git a/src/ort_genai.h b/src/ort_genai.h index 0ebf012641..cb90c5f279 100644 --- a/src/ort_genai.h +++ b/src/ort_genai.h @@ -420,14 +420,6 @@ struct OgaTokenizer : OgaAbstract { return p; } - OgaString ApplyChatTemplateWithOptions(const char* template_str, const char* messages, const char* tools, - const char* template_kwargs, bool add_generation_prompt) const { - const char* p{}; - OgaCheckResult(OgaTokenizerApplyChatTemplateWithOptions(this, template_str, messages, tools, template_kwargs, - add_generation_prompt, &p)); - return p; - } - #if OGA_USE_SPAN OgaString Decode(std::span tokens) const { const char* p; diff --git a/src/ort_genai_c.cpp b/src/ort_genai_c.cpp index 1fcf7b0952..9ac85fe48a 100644 --- a/src/ort_genai_c.cpp +++ b/src/ort_genai_c.cpp @@ -1048,17 +1048,6 @@ OgaResult* OGA_API_CALL OgaTokenizerApplyChatTemplate(const OgaTokenizer* tokeni OGA_CATCH } -OgaResult* OGA_API_CALL OgaTokenizerApplyChatTemplateWithOptions(const OgaTokenizer* tokenizer, const char* template_str, - const char* messages, const char* tools, - const char* template_kwargs, bool add_generation_prompt, - const char** out_string) { - OGA_TRY - *out_string = AllocOgaString(tokenizer->ApplyChatTemplateWithOptions(template_str, messages, tools, - template_kwargs, add_generation_prompt)); - return nullptr; - OGA_CATCH -} - OgaResult* OGA_API_CALL OgaTokenizerDecodeBatch(const OgaTokenizer* tokenizer, const OgaTensor* tensor, OgaStringArray** out) { OGA_TRY auto shape = tensor->GetShape(); diff --git a/src/ort_genai_c.h b/src/ort_genai_c.h index 2256d74b69..afa86408da 100644 --- a/src/ort_genai_c.h +++ b/src/ort_genai_c.h @@ -825,6 +825,11 @@ OGA_EXPORT void OGA_API_CALL OgaDestroyMultiModalProcessor(OgaMultiModalProcesso * - Values: `"true"` / `"false"` or `"1"` / `"0"`. * - Default: `"true"`. This is the default value set by ORT GenAI prior to any options updating. * + * - `chat_template_kwargs` + * - Purpose: Adds typed values to the chat template context. + * - Values: A C string containing serialized JSON text, such as `"{\"enable_thinking\":false}"`. + * - Default: `"{}"`. Set the value to `"{}"` to clear previously configured values. + * * Future tokenizer options may be added without changing this API signature. * Passing unknown keys will result in an error. */ @@ -994,20 +999,6 @@ OGA_EXPORT OgaResult* OGA_API_CALL OgaProcessorDecode(const OgaMultiModalProcess */ OGA_EXPORT OgaResult* OGA_API_CALL OgaTokenizerApplyChatTemplate(const OgaTokenizer*, const char* template_str, const char* messages, const char* tools, bool add_generation_prompt, const char** out_string); -/** - * @brief Applies a chat template to input messages with additional template context values. - * - * \param[in] tokenizer OgaTokenizer used for template processing. - * \param[in] template_str Null-terminated string representing the chat template. Use nullptr to fall back to the default chat template from the tokenizer config. - * \param[in] messages Null-terminated string containing the input messages to be processed. - * \param[in] tools Null-terminated string containing the chat function calls if any. Use nullptr if none. - * \param[in] template_kwargs Null-terminated JSON object containing additional template context values. Use nullptr if none. - * \param[in] add_generation_prompt Indicates whether to add a generation prompt to the output. - * \param[out] out_string Pointer to where the output will be stored. The returned pointer must be freed with OgaDestroyString. - * \return OgaResult* containing the error message if the function fails. - */ -OGA_EXPORT OgaResult* OGA_API_CALL OgaTokenizerApplyChatTemplateWithOptions(const OgaTokenizer*, const char* template_str, const char* messages, const char* tools, const char* template_kwargs, bool add_generation_prompt, const char** out_string); - /** OgaTokenizerStream is to decoded token strings incrementally, one token at a time. */ OGA_EXPORT OgaResult* OGA_API_CALL OgaCreateTokenizerStream(const OgaTokenizer*, OgaTokenizerStream** out); diff --git a/test/c_api_tests.cpp b/test/c_api_tests.cpp index c86c05a884..1d3c62c31a 100644 --- a/test/c_api_tests.cpp +++ b/test/c_api_tests.cpp @@ -248,15 +248,25 @@ TEST(CAPITests, ChatTemplate) { "|{{ reasoning_effort }}|{{ level }}"; const char* template_kwargs = R"({"enable_thinking":false,"reasoning_effort":"low","level":2})"; - auto kwargs_output = tokenizer->ApplyChatTemplateWithOptions( - kwargs_template, messages_json, nullptr, template_kwargs, true); + const char* option_keys[] = {"chat_template_kwargs"}; + const char* option_values[] = {template_kwargs}; + tokenizer->UpdateOptions(option_keys, option_values, 1); + auto kwargs_output = tokenizer->ApplyChatTemplate( + kwargs_template, messages_json, nullptr, true); ASSERT_STREQ("NO_THINK|low|2", kwargs_output); - auto legacy_output = tokenizer->ApplyChatTemplate( - "{{ messages[0].content }}", messages_json, nullptr, true); - auto null_options_output = tokenizer->ApplyChatTemplateWithOptions( - "{{ messages[0].content }}", messages_json, nullptr, nullptr, true); - ASSERT_STREQ(legacy_output, null_options_output); + option_values[0] = "{}"; + tokenizer->UpdateOptions(option_keys, option_values, 1); + auto cleared_output = tokenizer->ApplyChatTemplate( + "{% if enable_thinking is defined %}SET{% else %}CLEARED{% endif %}", + messages_json, nullptr, true); + ASSERT_STREQ("CLEARED", cleared_output); + + option_values[0] = template_kwargs; + tokenizer->UpdateOptions(option_keys, option_values, 1); + auto reapplied_output = tokenizer->ApplyChatTemplate( + kwargs_template, messages_json, nullptr, true); + ASSERT_STREQ("NO_THINK|low|2", reapplied_output); #endif }