@@ -105,8 +105,11 @@ def _create_pipeline(self) -> Pipeline:
105105 output_type = list ,
106106 ),
107107 )
108+ pipeline .add_component ("document_capture" , components .DocumentCapture ())
109+
108110 pipeline .connect ("query_embedder.embedding" , "retriever.query_embedding" )
109- pipeline .connect ("retriever.documents" , "output_adapter" )
111+ pipeline .connect ("retriever.documents" , "document_capture.documents" )
112+ pipeline .connect ("document_capture.documents" , "output_adapter" )
110113
111114 pipeline .add_component (
112115 "prompt_builder" ,
@@ -173,7 +176,7 @@ def run_api(
173176 pipeline_run_args ,
174177 user_id = user_email ,
175178 metadata = {"user_id" : user_email },
176- include_outputs_from = {"llm" , "save_result" },
179+ include_outputs_from = {"llm" , "save_result" , "retriever" },
177180 input_ = query ,
178181 extract_output = extract_output ,
179182 parent_span_name_suffix = suffix ,
@@ -192,6 +195,7 @@ def create_pipeline_args(
192195 llm_model : str | None = None ,
193196 reasoning_effort : str | None = None ,
194197 streaming : bool = False ,
198+ result_id : str | None = None ,
195199 ) -> dict :
196200 """Create pipeline run arguments with optional overrides for model, reasoning effort, and streaming."""
197201 assert suffix , "suffix is required"
@@ -207,7 +211,7 @@ def create_pipeline_args(
207211 detail = f"The requested prompt version '{ prompt_version_id } ' with suffix '{ suffix } ' could not be retrieved" ,
208212 ) from e
209213
210- return {
214+ args = {
211215 "logger" : {
212216 "messages_list" : [{"query" : query , "user_email" : user_email }],
213217 },
@@ -230,6 +234,10 @@ def create_pipeline_args(
230234 "filters" : {"field" : "region" , "operator" : "==" , "value" : region },
231235 },
232236 }
237+ if result_id :
238+ args ["save_result" ] = {"result_id" : result_id }
239+ args ["document_capture" ] = {"result_id" : result_id }
240+ return args
233241
234242 # https://docs.haystack.deepset.ai/docs/hayhooks#openai-compatibility
235243 # This function is called for the `{pipeline_name}/chat`, `/chat/completions`, or `/v1/chat/completions` streaming endpoint using Server-Sent Events (SSE)
@@ -249,6 +257,8 @@ def run_chat_completion(self, model: str, messages: list, body: dict) -> Generat
249257 if not user_email :
250258 raise ValueError ("user_email parameter is required" )
251259
260+ # Generate result_id upfront to pass to both SaveResult and DocumentCapture via pipeline args
261+ result_id = str (uuid .uuid4 ())
252262 pipeline_run_args = self .create_pipeline_args (
253263 query ,
254264 user_email ,
@@ -258,12 +268,9 @@ def run_chat_completion(self, model: str, messages: list, body: dict) -> Generat
258268 llm_model = body .get ("llm_model" , None ),
259269 reasoning_effort = body .get ("reasoning_effort" , None ),
260270 streaming = True ,
271+ result_id = result_id ,
261272 )
262273
263- # Generate result_id upfront to pass to both SaveResult and the hook
264- result_id = str (uuid .uuid4 ())
265- pipeline_run_args ["save_result" ] = {"result_id" : result_id }
266-
267274 logger .info ("Streaming referrals: %s" , pipeline_run_args )
268275 return self .runner .stream_response (
269276 pipeline_run_args ,
@@ -272,5 +279,13 @@ def run_chat_completion(self, model: str, messages: list, body: dict) -> Generat
272279 input_ = query ,
273280 shorten_output = shorten_output ,
274281 parent_span_name_suffix = suffix ,
275- generator_hook = haystack_utils .create_result_id_hook (self .pipeline , result_id ),
282+ generator_hook = haystack_utils .create_result_id_hook (
283+ self .pipeline ,
284+ result_id ,
285+ pop_documents_fn = lambda : {"documents" : components .DocumentCapture .pop (result_id )},
286+ ),
287+ # No-op if the hook already ran (pop returns [] for missing keys).
288+ # Ensures the DocumentCapture entry is always removed even when the pipeline
289+ # raises before the hook executes.
290+ cleanup_fn = lambda : components .DocumentCapture .pop (result_id ),
276291 )
0 commit comments