From 52acf840a6b15e86a507f55c26662a2301cafcef Mon Sep 17 00:00:00 2001 From: suh016 Date: Mon, 4 May 2026 17:11:42 +0800 Subject: [PATCH] Allow callers to pass tokenizer_options in Text2TextGenerationPipeline The tokenizer call inside _call() previously used hardcoded options with no way to override them. Now callers can pass tokenizer_options alongside generation kwargs to control things like max_length and truncation_side. tokenizer_options is extracted from generate_kwargs before model.generate() is called so it never leaks into GenerationFunctionParameters. Pipeline defaults (padding: true, truncation: true) still apply and caller values take precedence. Closes #1096. --- .../src/pipelines/text2text-generation.js | 11 +++++++++-- .../test_pipelines_text2text_generation.js | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/transformers/src/pipelines/text2text-generation.js b/packages/transformers/src/pipelines/text2text-generation.js index b313dd91f..700c59552 100644 --- a/packages/transformers/src/pipelines/text2text-generation.js +++ b/packages/transformers/src/pipelines/text2text-generation.js @@ -72,16 +72,23 @@ export class Text2TextGenerationPipeline } const tokenizer = this.tokenizer; + + // Callers may pass tokenizer_options as a top-level key inside generate_kwargs to + // control tokenization (e.g. max_length, truncation side) without touching generation + // parameters. We extract it here so it never leaks into model.generate(). + const { tokenizer_options: caller_tokenizer_options, ...rest_generate_kwargs } = generate_kwargs; const tokenizer_options = { padding: true, truncation: true, + ...caller_tokenizer_options, }; + let inputs; if (this.task === 'translation' && '_build_translation_inputs' in tokenizer) { // TODO: move to Translation pipeline? // Currently put here to avoid code duplication // @ts-ignore - inputs = tokenizer._build_translation_inputs(texts, tokenizer_options, generate_kwargs); + inputs = tokenizer._build_translation_inputs(texts, tokenizer_options, rest_generate_kwargs); } else { inputs = tokenizer(texts, tokenizer_options); } @@ -89,7 +96,7 @@ export class Text2TextGenerationPipeline const outputTokenIds = await this.model.generate({ ...inputs, ...this._default_generation_config, - ...generate_kwargs, + ...rest_generate_kwargs, }); return tokenizer .batch_decode(/** @type {Tensor} */ (outputTokenIds), { diff --git a/packages/transformers/tests/pipelines/test_pipelines_text2text_generation.js b/packages/transformers/tests/pipelines/test_pipelines_text2text_generation.js index d8d756f34..3abd4e033 100644 --- a/packages/transformers/tests/pipelines/test_pipelines_text2text_generation.js +++ b/packages/transformers/tests/pipelines/test_pipelines_text2text_generation.js @@ -31,6 +31,24 @@ export default () => { }, MAX_TEST_EXECUTION_TIME, ); + + it( + "tokenizer_options are forwarded to the tokenizer", + async () => { + const text = "This is a test."; + // max_length=3 forces aggressive truncation via tokenizer_options; + // the model should still run without error and return a string result. + // tokenizer_options is extracted before generate() is called so it + // never leaks into GenerationFunctionParameters. + const output = await pipe(text, { + max_new_tokens: 5, + tokenizer_options: { truncation: true, max_length: 3 }, + }); + expect(Array.isArray(output)).toBe(true); + expect(typeof output[0].generated_text).toBe("string"); + }, + MAX_TEST_EXECUTION_TIME, + ); }); afterAll(async () => {