This is an automated email from the ASF dual-hosted git repository.
shahar1 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 378541bd1fe Fix CohereEmbeddingOperator input_text normalization
before rendering (#70325)
378541bd1fe is described below
commit 378541bd1fe319f61e22bbb68f7f523513310056
Author: Parman Mohammadalizadeh <[email protected]>
AuthorDate: Fri Jul 24 11:48:09 2026 +0330
Fix CohereEmbeddingOperator input_text normalization before rendering
(#70325)
input_text is a template field, rendered after __init__ runs. Wrapping a
single string into a list in the constructor acts on the un-rendered Jinja
expression, so a templated input_text is mis-wrapped before it resolves.
Move the normalization into execute() so it runs on the rendered value.
---
.../providers/cohere/operators/embedding.py | 7 +++---
.../tests/unit/cohere/operators/test_embedding.py | 26 ++++++++++++++++++++++
.../ci/prek/validate_operators_init_exemptions.txt | 1 -
3 files changed, 30 insertions(+), 4 deletions(-)
diff --git
a/providers/cohere/src/airflow/providers/cohere/operators/embedding.py
b/providers/cohere/src/airflow/providers/cohere/operators/embedding.py
index 62270e75708..312f9237c55 100644
--- a/providers/cohere/src/airflow/providers/cohere/operators/embedding.py
+++ b/providers/cohere/src/airflow/providers/cohere/operators/embedding.py
@@ -68,8 +68,6 @@ class CohereEmbeddingOperator(BaseOperator):
**kwargs: Any,
):
super().__init__(**kwargs)
- if isinstance(input_text, str):
- input_text = [input_text]
self.conn_id = conn_id
self.input_text = input_text
self.timeout = timeout
@@ -88,7 +86,10 @@ class CohereEmbeddingOperator(BaseOperator):
def execute(self, context: Context) -> list[list[float]]:
"""Embed texts using Cohere embed services."""
- embedding_response = self.hook.create_embeddings(self.input_text)
+ # input_text is a template field, so normalize a single string into a
list here
+ # (after rendering) rather than in __init__, where it would act on the
un-rendered value.
+ input_text = [self.input_text] if isinstance(self.input_text, str)
else self.input_text
+ embedding_response = self.hook.create_embeddings(input_text)
# NOTE: Return type `EmbedByTypeResponseEmbeddings` was removed
temporarily due to limitations
# in XCom serialization/deserialization of complex types like Cohere
embeddings and Pydantic models.
#
diff --git a/providers/cohere/tests/unit/cohere/operators/test_embedding.py
b/providers/cohere/tests/unit/cohere/operators/test_embedding.py
index 1b6bf810e93..be971bde883 100644
--- a/providers/cohere/tests/unit/cohere/operators/test_embedding.py
+++ b/providers/cohere/tests/unit/cohere/operators/test_embedding.py
@@ -56,3 +56,29 @@ def test_cohere_embedding_operator(cohere_client,
get_connection):
val = op.execute(context={})
cohere_client.assert_called_once_with(api_key=api_key, base_url=base_url,
timeout=timeout)
assert val == embedded_obj
+
+
+@patch("airflow.providers.cohere.operators.embedding.CohereEmbeddingOperator.hook")
+def test_single_string_input_text_normalized_at_execute(mock_hook):
+ """
+ A single-string ``input_text`` is wrapped into a list in ``execute()``
(after templating),
+ not in ``__init__``. ``input_text`` is a template field, so wrapping it in
the constructor
+ would operate on the un-rendered Jinja expression.
+ """
+ op = CohereEmbeddingOperator(task_id="embed", conn_id="some_conn",
input_text="single text")
+
+ # __init__ keeps the value verbatim; the list normalization is deferred to
execute().
+ assert op.input_text == "single text"
+
+ op.execute(context={})
+ mock_hook.create_embeddings.assert_called_once_with(["single text"])
+
+
+@patch("airflow.providers.cohere.operators.embedding.CohereEmbeddingOperator.hook")
+def test_list_input_text_passed_through_at_execute(mock_hook):
+ """A list ``input_text`` is passed to the hook unchanged."""
+ texts = ["first", "second"]
+ op = CohereEmbeddingOperator(task_id="embed", conn_id="some_conn",
input_text=texts)
+
+ op.execute(context={})
+ mock_hook.create_embeddings.assert_called_once_with(texts)
diff --git a/scripts/ci/prek/validate_operators_init_exemptions.txt
b/scripts/ci/prek/validate_operators_init_exemptions.txt
index db9e1ad7ce8..7f5f7bc618c 100644
--- a/scripts/ci/prek/validate_operators_init_exemptions.txt
+++ b/scripts/ci/prek/validate_operators_init_exemptions.txt
@@ -27,7 +27,6 @@
providers/apache/hive/src/airflow/providers/apache/hive/sensors/named_hive_parti
providers/apache/kafka/src/airflow/providers/apache/kafka/operators/produce.py::ProduceToTopicOperator
providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/operators/kueue.py::KubernetesInstallKueueOperator
providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/operators/pod.py::KubernetesPodOperator
-providers/cohere/src/airflow/providers/cohere/operators/embedding.py::CohereEmbeddingOperator
providers/databricks/src/airflow/providers/databricks/operators/databricks_repos.py::DatabricksReposCreateOperator
providers/databricks/src/airflow/providers/databricks/operators/databricks_repos.py::DatabricksReposDeleteOperator
providers/databricks/src/airflow/providers/databricks/operators/databricks_repos.py::DatabricksReposUpdateOperator