@@ -48,7 +48,7 @@ def __init__(
4848 * ,
4949 chat_generator : ChatGenerator ,
5050 system_prompt : str | None = None ,
51- user_prompt : str ,
51+ user_prompt : str | None = None ,
5252 required_variables : list [str ] | Literal ["*" ] = "*" ,
5353 streaming_callback : StreamingCallbackT | None = None ,
5454 ) -> None :
@@ -57,21 +57,18 @@ def __init__(
5757
5858 :param chat_generator: An instance of the chat generator that the LLM should use.
5959 :param system_prompt: System prompt for the LLM.
60- :param user_prompt: User prompt for the LLM. Must contain at least one Jinja2 template variable
61- (e.g., ``{{ variable_name }}``). This prompt is appended to the messages provided at runtime.
60+ :param user_prompt: User prompt for the LLM. This prompt is appended to the messages provided at
61+ runtime. If it contains Jinja2 template variables (e.g., `{{ variable_name }}`), they become
62+ inputs to the component. If omitted or if there are no template variables, `messages` must be
63+ provided at runtime instead.
6264 :param required_variables:
6365 Variables that must be provided as input to user_prompt.
6466 If a variable listed as required is not provided, an exception is raised.
65- If set to ``"*"``, all variables found in the prompt are required. Defaults to ``"*"``.
67+ If set to `"*"`, all variables found in the prompt are required. Defaults to `"*"`.
68+ Only relevant when `user_prompt` contains template variables.
6669 :param streaming_callback: A callback that will be invoked when a response is streamed from the LLM.
67- :raises ValueError: If user_prompt contains no template variables.
68- :raises ValueError: If required_variables is an empty list.
70+ :raises ValueError: If user_prompt contains template variables but required_variables is an empty list.
6971 """
70- if isinstance (required_variables , list ) and len (required_variables ) == 0 :
71- raise ValueError (
72- "required_variables must not be empty. Set it to '*' to require all variables, "
73- "or provide a non-empty list of variable names."
74- )
7572 super (LLM , self ).__init__ ( # noqa: UP008
7673 chat_generator = chat_generator ,
7774 system_prompt = system_prompt ,
@@ -80,11 +77,17 @@ def __init__(
8077 streaming_callback = streaming_callback ,
8178 )
8279 if self ._user_chat_prompt_builder is None or len (self ._user_chat_prompt_builder .variables ) == 0 :
83- raise ValueError (
84- "user_prompt must contain at least one template variable (e.g., '{{ variable_name }}'). "
85- "The LLM component requires at least one required input variable to ensure proper "
86- "pipeline scheduling."
87- )
80+ # This means user_prompt is empty or has no template variables.
81+ # To ensure properly scheduling we then require messages to be passed at runtime.
82+ component .set_input_type (self , "messages" , list [ChatMessage ])
83+ else :
84+ # user prompt was provided with variables
85+ if isinstance (required_variables , list ) and len (required_variables ) == 0 :
86+ raise ValueError (
87+ "required_variables must not be empty. Set it to '*' to require all variables, "
88+ "or provide a non-empty list of variable names."
89+ )
90+ component .set_input_type (self , "messages" , list [ChatMessage ], None )
8891
8992 def to_dict (self ) -> dict [str , Any ]:
9093 """
@@ -118,11 +121,10 @@ def from_dict(cls, data: dict[str, Any]) -> "LLM":
118121
119122 return default_from_dict (cls , data )
120123
121- def run (
124+ def run ( # type: ignore[override] # `messages` is in **kwargs to allow dynamic required/optional status
122125 self ,
123- messages : list [ChatMessage ] | None = None ,
124- streaming_callback : StreamingCallbackT | None = None ,
125126 * ,
127+ streaming_callback : StreamingCallbackT | None = None ,
126128 generation_kwargs : dict [str , Any ] | None = None ,
127129 system_prompt : str | None = None ,
128130 user_prompt : str | None = None ,
@@ -131,7 +133,9 @@ def run(
131133 """
132134 Process messages and generate a response from the language model.
133135
134- :param messages: List of Haystack ChatMessage objects to process.
136+ :param messages: Optional list of ChatMessage objects to prepend to the conversation. Whether this is
137+ required or optional depends on the `user_prompt` configuration: if `user_prompt` has no template
138+ variables, `messages` must be provided. Passed via `**kwargs`.
135139 :param streaming_callback: A callback that will be invoked when a response is streamed from the LLM.
136140 :param generation_kwargs: Additional keyword arguments for the underlying chat generator. These parameters
137141 will override the parameters passed during component initialization.
@@ -145,6 +149,9 @@ def run(
145149 - "messages": List of all messages exchanged during the LLM's run.
146150 - "last_message": The last message exchanged during the LLM's run.
147151 """
152+ # `messages` is intentionally omitted from the signature so the framework can treat it as required
153+ # or optional depending on init configuration. See __init__ for details.
154+ messages = kwargs .pop ("messages" , None )
148155 return super (LLM , self ).run ( # noqa: UP008
149156 messages = messages or [],
150157 streaming_callback = streaming_callback ,
@@ -154,11 +161,10 @@ def run(
154161 ** kwargs ,
155162 )
156163
157- async def run_async (
164+ async def run_async ( # type: ignore[override] # `messages` is in **kwargs to allow dynamic required/optional status
158165 self ,
159- messages : list [ChatMessage ] | None = None ,
160- streaming_callback : StreamingCallbackT | None = None ,
161166 * ,
167+ streaming_callback : StreamingCallbackT | None = None ,
162168 generation_kwargs : dict [str , Any ] | None = None ,
163169 system_prompt : str | None = None ,
164170 user_prompt : str | None = None ,
@@ -167,7 +173,9 @@ async def run_async(
167173 """
168174 Asynchronously process messages and generate a response from the language model.
169175
170- :param messages: List of Haystack ChatMessage objects to process.
176+ :param messages: Optional list of ChatMessage objects to prepend to the conversation. Whether this is
177+ required or optional depends on the `user_prompt` configuration: if `user_prompt` has no template
178+ variables, `messages` must be provided. Passed via `**kwargs`.
171179 :param streaming_callback: An asynchronous callback that will be invoked when a response is streamed
172180 from the LLM.
173181 :param generation_kwargs: Additional keyword arguments for the underlying chat generator. These parameters
@@ -182,6 +190,9 @@ async def run_async(
182190 - "messages": List of all messages exchanged during the LLM's run.
183191 - "last_message": The last message exchanged during the LLM's run.
184192 """
193+ # `messages` is intentionally omitted from the signature so the framework can treat it as required
194+ # or optional depending on init configuration. See __init__ for details.
195+ messages = kwargs .pop ("messages" , None )
185196 return await super (LLM , self ).run_async ( # noqa: UP008
186197 messages = messages or [],
187198 streaming_callback = streaming_callback ,
0 commit comments