xgae 0.1.4__py3-none-any.whl → 0.1.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of xgae might be problematic. Click here for more details.

@@ -2,17 +2,61 @@ import asyncio
2
2
  import json
3
3
  import logging
4
4
  import uuid
5
+
6
+ from dataclasses import dataclass
5
7
  from datetime import datetime, timezone
6
- from typing import List, Dict, Any, Optional, AsyncGenerator, override
8
+ from typing import List, Dict, Any, Optional, AsyncGenerator, override, Literal
7
9
 
8
- from xgae.engine.responser.xga_responser_base import TaskResponseProcessor, ProcessorConfig, TaskResponseContext,TaskRunContinuousState
10
+ from xgae.utils import langfuse
11
+ from xgae.engine.responser.responser_base import TaskResponseProcessor, TaskResponserContext,TaskRunContinuousState,XmlAddingStrategy,ToolExecutionStrategy
9
12
  from xgae.utils.json_helpers import (
10
13
  ensure_dict, safe_json_parse,
11
14
  to_json_string, format_for_yield
12
15
  )
13
16
 
17
+ @dataclass
18
+ class ProcessorConfig:
19
+ """
20
+ Configuration for response processing and tool execution.
21
+
22
+ This class controls how the LLM's responses are processed, including how tool calls
23
+ are detected, executed, and their results handled.
24
+
25
+ Attributes:
26
+ xml_tool_calling: Enable XML-based tool call detection (<tool>...</tool>)
27
+ native_tool_calling: Enable OpenAI-style function calling format
28
+ execute_tools: Whether to automatically execute detected tool calls
29
+ execute_on_stream: For streaming, execute tools as they appear vs. at the end
30
+ tool_execution_strategy: How to execute multiple tools ("sequential" or "parallel")
31
+ xml_adding_strategy: How to add XML tool results to the conversation
32
+ max_xml_tool_calls: Maximum number of XML tool calls to process (0 = no limit)
33
+ """
34
+
35
+ xml_tool_calling: bool = True
36
+ native_tool_calling: bool = False
37
+
38
+ execute_tools: bool = True
39
+ execute_on_stream: bool = False
40
+ tool_execution_strategy: ToolExecutionStrategy = "sequential"
41
+ xml_adding_strategy: XmlAddingStrategy = "assistant_message"
42
+ max_xml_tool_calls: int = 0 # 0 means no limit
43
+
44
+ def __post_init__(self):
45
+ """Validate configuration after initialization."""
46
+ if self.xml_tool_calling is False and self.native_tool_calling is False and self.execute_tools:
47
+ raise ValueError(
48
+ "At least one tool calling format (XML or native) must be enabled if execute_tools is True")
49
+
50
+ if self.xml_adding_strategy not in ["user_message", "assistant_message", "inline_edit"]:
51
+ raise ValueError("xml_adding_strategy must be 'user_message', 'assistant_message', or 'inline_edit'")
52
+
53
+ if self.max_xml_tool_calls < 0:
54
+ raise ValueError("max_xml_tool_calls must be a non-negative integer (0 = no limit)")
55
+
56
+
57
+
14
58
  class StreamTaskResponser(TaskResponseProcessor):
15
- def __init__(self, response_context: TaskResponseContext):
59
+ def __init__(self, response_context: TaskResponserContext):
16
60
  super().__init__(response_context)
17
61
 
18
62
  @override
@@ -86,14 +130,14 @@ class StreamTaskResponser(TaskResponseProcessor):
86
130
  # --- Save and Yield Start Events (only if not auto-continuing) ---
87
131
  if auto_continue_count == 0:
88
132
  start_content = {"status_type": "thread_run_start", "thread_run_id": thread_run_id}
89
- start_msg_obj = await self.add_message(
133
+ start_msg_obj = await self.add_response_message(
90
134
  type="status", content=start_content,
91
135
  is_llm_message=False, metadata={"thread_run_id": thread_run_id}
92
136
  )
93
137
  if start_msg_obj: yield format_for_yield(start_msg_obj)
94
138
 
95
139
  assist_start_content = {"status_type": "assistant_response_start"}
96
- assist_start_msg_obj = await self.add_message(
140
+ assist_start_msg_obj = await self.add_response_message(
97
141
  type="status", content=assist_start_content,
98
142
  is_llm_message=False, metadata={"thread_run_id": thread_run_id}
99
143
  )
@@ -161,7 +205,7 @@ class StreamTaskResponser(TaskResponseProcessor):
161
205
  __sequence += 1
162
206
  else:
163
207
  logging.info("XML tool call limit reached - not yielding more content chunks")
164
- self.trace.event(name="xml_tool_call_limit_reached", level="DEFAULT", status_message=(
208
+ langfuse.create_event(trace_context=self.trace_context, name="xml_tool_call_limit_reached", level="DEFAULT", status_message=(
165
209
  f"XML tool call limit reached - not yielding more content chunks"))
166
210
 
167
211
  # --- Process XML Tool Calls (if enabled and limit not reached) ---
@@ -183,8 +227,7 @@ class StreamTaskResponser(TaskResponseProcessor):
183
227
 
184
228
  if config.execute_tools and config.execute_on_stream:
185
229
  # Save and Yield tool_started status
186
- started_msg_obj = await self._yield_and_save_tool_started(context, thread_id,
187
- thread_run_id)
230
+ started_msg_obj = await self._add_tool_start_message(context)
188
231
  if started_msg_obj: yield format_for_yield(started_msg_obj)
189
232
  yielded_tool_indices.add(tool_index) # Mark status as yielded
190
233
 
@@ -261,8 +304,7 @@ class StreamTaskResponser(TaskResponseProcessor):
261
304
  )
262
305
 
263
306
  # Save and Yield tool_started status
264
- started_msg_obj = await self._yield_and_save_tool_started(context, thread_id,
265
- thread_run_id)
307
+ started_msg_obj = await self._add_tool_start_message(context)
266
308
  if started_msg_obj: yield format_for_yield(started_msg_obj)
267
309
  yielded_tool_indices.add(tool_index) # Mark status as yielded
268
310
 
@@ -275,7 +317,7 @@ class StreamTaskResponser(TaskResponseProcessor):
275
317
 
276
318
  if finish_reason == "xml_tool_limit_reached":
277
319
  logging.info("Stopping stream processing after loop due to XML tool call limit")
278
- self.trace.event(name="stopping_stream_processing_after_loop_due_to_xml_tool_call_limit",
320
+ langfuse.create_event(trace_context=self.trace_context, name="stopping_stream_processing_after_loop_due_to_xml_tool_call_limit",
279
321
  level="DEFAULT", status_message=(
280
322
  f"Stopping stream processing after loop due to XML tool call limit"))
281
323
  break
@@ -310,18 +352,18 @@ class StreamTaskResponser(TaskResponseProcessor):
310
352
  # f"🔥 Estimated tokens – prompt: {prompt_tokens}, "
311
353
  # f"completion: {completion_tokens}, total: {prompt_tokens + completion_tokens}"
312
354
  # )
313
- self.trace.event(name="usage_calculated_with_litellm_token_counter", level="DEFAULT",
355
+ langfuse.create_event(trace_context=self.trace_context, name="usage_calculated_with_litellm_token_counter", level="DEFAULT",
314
356
  status_message=(f"Usage calculated with litellm.token_counter"))
315
357
  except Exception as e:
316
358
  logging.warning(f"Failed to calculate usage: {str(e)}")
317
- self.trace.event(name="failed_to_calculate_usage", level="WARNING",
359
+ langfuse.create_event(trace_context=self.trace_context, name="failed_to_calculate_usage", level="WARNING",
318
360
  status_message=(f"Failed to calculate usage: {str(e)}"))
319
361
 
320
362
  # Wait for pending tool executions from streaming phase
321
363
  tool_results_buffer = [] # Stores (tool_call, result, tool_index, context)
322
364
  if pending_tool_executions:
323
365
  logging.info(f"Waiting for {len(pending_tool_executions)} pending streamed tool executions")
324
- self.trace.event(name="waiting_for_pending_streamed_tool_executions", level="DEFAULT", status_message=(
366
+ langfuse.create_event(trace_context=self.trace_context, name="waiting_for_pending_streamed_tool_executions", level="DEFAULT", status_message=(
325
367
  f"Waiting for {len(pending_tool_executions)} pending streamed tool executions"))
326
368
  # ... (asyncio.wait logic) ...
327
369
  pending_tasks = [execution["task"] for execution in pending_tool_executions]
@@ -345,24 +387,24 @@ class StreamTaskResponser(TaskResponseProcessor):
345
387
  if tool_name in ['ask', 'complete']:
346
388
  logging.info(
347
389
  f"Terminating tool '{tool_name}' completed during streaming. Setting termination flag.")
348
- self.trace.event(name="terminating_tool_completed_during_streaming",
390
+ langfuse.create_event(trace_context=self.trace_context, name="terminating_tool_completed_during_streaming",
349
391
  level="DEFAULT", status_message=(
350
392
  f"Terminating tool '{tool_name}' completed during streaming. Setting termination flag."))
351
393
  agent_should_terminate = True
352
394
 
353
395
  else: # Should not happen with asyncio.wait
354
396
  logging.warning(f"Task for tool index {tool_idx} not done after wait.")
355
- self.trace.event(name="task_for_tool_index_not_done_after_wait", level="WARNING",
397
+ langfuse.create_event(trace_context=self.trace_context, name="task_for_tool_index_not_done_after_wait", level="WARNING",
356
398
  status_message=(
357
399
  f"Task for tool index {tool_idx} not done after wait."))
358
400
  except Exception as e:
359
401
  logging.error(f"Error getting result for pending tool execution {tool_idx}: {str(e)}")
360
- self.trace.event(name="error_getting_result_for_pending_tool_execution", level="ERROR",
402
+ langfuse.create_event(trace_context=self.trace_context, name="error_getting_result_for_pending_tool_execution", level="ERROR",
361
403
  status_message=(
362
404
  f"Error getting result for pending tool execution {tool_idx}: {str(e)}"))
363
405
  context.error = e
364
406
  # Save and Yield tool error status message (even if started was yielded)
365
- error_msg_obj = await self._yield_and_save_tool_error(context, thread_id, thread_run_id)
407
+ error_msg_obj = await self._add_tool_error_message(context)
366
408
  if error_msg_obj: yield format_for_yield(error_msg_obj)
367
409
  continue # Skip further status yielding for this tool index
368
410
 
@@ -377,40 +419,39 @@ class StreamTaskResponser(TaskResponseProcessor):
377
419
  if tool_name in ['ask', 'complete']:
378
420
  logging.info(
379
421
  f"Terminating tool '{tool_name}' completed during streaming. Setting termination flag.")
380
- self.trace.event(name="terminating_tool_completed_during_streaming", level="DEFAULT",
422
+ langfuse.create_event(trace_context=self.trace_context, name="terminating_tool_completed_during_streaming", level="DEFAULT",
381
423
  status_message=(
382
424
  f"Terminating tool '{tool_name}' completed during streaming. Setting termination flag."))
383
425
  agent_should_terminate = True
384
426
 
385
427
  # Save and Yield tool completed/failed status
386
- completed_msg_obj = await self._yield_and_save_tool_completed(
387
- context, None, thread_id, thread_run_id
388
- )
428
+ completed_msg_obj = await self._add_tool_completed_message(
429
+ context, None)
389
430
  if completed_msg_obj: yield format_for_yield(completed_msg_obj)
390
431
  yielded_tool_indices.add(tool_idx)
391
432
  except Exception as e:
392
433
  logging.error(
393
434
  f"Error getting result/yielding status for pending tool execution {tool_idx}: {str(e)}")
394
- self.trace.event(name="error_getting_result_yielding_status_for_pending_tool_execution",
435
+ langfuse.create_event(trace_context=self.trace_context, name="error_getting_result_yielding_status_for_pending_tool_execution",
395
436
  level="ERROR", status_message=(
396
437
  f"Error getting result/yielding status for pending tool execution {tool_idx}: {str(e)}"))
397
438
  context.error = e
398
439
  # Save and Yield tool error status
399
- error_msg_obj = await self._yield_and_save_tool_error(context, thread_id, thread_run_id)
440
+ error_msg_obj = await self._add_tool_error_message(context)
400
441
  if error_msg_obj: yield format_for_yield(error_msg_obj)
401
442
  yielded_tool_indices.add(tool_idx)
402
443
 
403
444
  # Save and yield finish status if limit was reached
404
445
  if finish_reason == "xml_tool_limit_reached":
405
446
  finish_content = {"status_type": "finish", "finish_reason": "xml_tool_limit_reached"}
406
- finish_msg_obj = await self.add_message(
447
+ finish_msg_obj = await self.add_response_message(
407
448
  type="status", content=finish_content,
408
449
  is_llm_message=False, metadata={"thread_run_id": thread_run_id}
409
450
  )
410
451
  if finish_msg_obj: yield format_for_yield(finish_msg_obj)
411
452
  logging.info(
412
453
  f"Stream finished with reason: xml_tool_limit_reached after {xml_tool_call_count} XML tool calls")
413
- self.trace.event(name="stream_finished_with_reason_xml_tool_limit_reached_after_xml_tool_calls",
454
+ langfuse.create_event(trace_context=self.trace_context, name="stream_finished_with_reason_xml_tool_limit_reached_after_xml_tool_calls",
414
455
  level="DEFAULT", status_message=(
415
456
  f"Stream finished with reason: xml_tool_limit_reached after {xml_tool_call_count} XML tool calls"))
416
457
 
@@ -446,7 +487,7 @@ class StreamTaskResponser(TaskResponseProcessor):
446
487
  "tool_calls": complete_native_tool_calls or None
447
488
  }
448
489
 
449
- last_assistant_message_object = await self._add_message_with_agent_info(type="assistant", content=message_data,
490
+ last_assistant_message_object = await self.add_response_message(type="assistant", content=message_data,
450
491
  is_llm_message=True, metadata={"thread_run_id": thread_run_id}
451
492
  )
452
493
 
@@ -460,12 +501,12 @@ class StreamTaskResponser(TaskResponseProcessor):
460
501
  yield format_for_yield(yield_message)
461
502
  else:
462
503
  logging.error(f"Failed to save final assistant message for thread {thread_id}")
463
- self.trace.event(name="failed_to_save_final_assistant_message_for_thread", level="ERROR",
504
+ langfuse.create_event(trace_context=self.trace_context, name="failed_to_save_final_assistant_message_for_thread", level="ERROR",
464
505
  status_message=(f"Failed to save final assistant message for thread {thread_id}"))
465
506
  # Save and yield an error status
466
507
  err_content = {"role": "system", "status_type": "error",
467
508
  "message": "Failed to save final assistant message"}
468
- err_msg_obj = await self.add_message(
509
+ err_msg_obj = await self.add_response_message(
469
510
  type="status", content=err_content,
470
511
  is_llm_message=False, metadata={"thread_run_id": thread_run_id}
471
512
  )
@@ -528,7 +569,7 @@ class StreamTaskResponser(TaskResponseProcessor):
528
569
  # Populate from buffer if executed on stream
529
570
  if config.execute_on_stream and tool_results_buffer:
530
571
  logging.info(f"Processing {len(tool_results_buffer)} buffered tool results")
531
- self.trace.event(name="processing_buffered_tool_results", level="DEFAULT",
572
+ langfuse.create_event(trace_context=self.trace_context, name="processing_buffered_tool_results", level="DEFAULT",
532
573
  status_message=(f"Processing {len(tool_results_buffer)} buffered tool results"))
533
574
  for tool_call, result, tool_idx, context in tool_results_buffer:
534
575
  if last_assistant_message_object: context.assistant_message_id = last_assistant_message_object[
@@ -539,7 +580,7 @@ class StreamTaskResponser(TaskResponseProcessor):
539
580
  elif final_tool_calls_to_process and not config.execute_on_stream:
540
581
  logging.info(
541
582
  f"Executing {len(final_tool_calls_to_process)} tools ({config.tool_execution_strategy}) after stream")
542
- self.trace.event(name="executing_tools_after_stream", level="DEFAULT", status_message=(
583
+ langfuse.create_event(trace_context=self.trace_context, name="executing_tools_after_stream", level="DEFAULT", status_message=(
543
584
  f"Executing {len(final_tool_calls_to_process)} tools ({config.tool_execution_strategy}) after stream"))
544
585
  results_list = await self._execute_tools(final_tool_calls_to_process,
545
586
  config.tool_execution_strategy)
@@ -557,14 +598,14 @@ class StreamTaskResponser(TaskResponseProcessor):
557
598
  tool_results_map[current_tool_idx] = (tc, res, context)
558
599
  else:
559
600
  logging.warning(f"Could not map result for tool index {current_tool_idx}")
560
- self.trace.event(name="could_not_map_result_for_tool_index", level="WARNING",
601
+ langfuse.create_event(trace_context=self.trace_context, name="could_not_map_result_for_tool_index", level="WARNING",
561
602
  status_message=(f"Could not map result for tool index {current_tool_idx}"))
562
603
  current_tool_idx += 1
563
604
 
564
605
  # Save and Yield each result message
565
606
  if tool_results_map:
566
607
  logging.info(f"Saving and yielding {len(tool_results_map)} final tool result messages")
567
- self.trace.event(name="saving_and_yielding_final_tool_result_messages", level="DEFAULT",
608
+ langfuse.create_event(trace_context=self.trace_context, name="saving_and_yielding_final_tool_result_messages", level="DEFAULT",
568
609
  status_message=(
569
610
  f"Saving and yielding {len(tool_results_map)} final tool result messages"))
570
611
  for tool_idx in sorted(tool_results_map.keys()):
@@ -575,21 +616,19 @@ class StreamTaskResponser(TaskResponseProcessor):
575
616
 
576
617
  # Yield start status ONLY IF executing non-streamed (already yielded if streamed)
577
618
  if not config.execute_on_stream and tool_idx not in yielded_tool_indices:
578
- started_msg_obj = await self._yield_and_save_tool_started(context, thread_id, thread_run_id)
619
+ started_msg_obj = await self._add_tool_start_message(context)
579
620
  if started_msg_obj: yield format_for_yield(started_msg_obj)
580
621
  yielded_tool_indices.add(tool_idx) # Mark status yielded
581
622
 
582
623
  # Save the tool result message to DB
583
- saved_tool_result_object = await self._add_tool_result( # Returns full object or None
584
- thread_id, tool_call, result, config.xml_adding_strategy,
585
- context.assistant_message_id, context.parsing_details
586
- )
624
+ saved_tool_result_object = await self._add_tool_messsage(tool_call, result, config.xml_adding_strategy,
625
+ context.assistant_message_id, context.parsing_details
626
+ )
587
627
 
588
628
  # Yield completed/failed status (linked to saved result ID if available)
589
- completed_msg_obj = await self._yield_and_save_tool_completed(
629
+ completed_msg_obj = await self._add_tool_completed_message(
590
630
  context,
591
- saved_tool_result_object['message_id'] if saved_tool_result_object else None,
592
- thread_id, thread_run_id
631
+ saved_tool_result_object['message_id'] if saved_tool_result_object else None
593
632
  )
594
633
  if completed_msg_obj: yield format_for_yield(completed_msg_obj)
595
634
  # Don't add to yielded_tool_indices here, completion status is separate yield
@@ -601,7 +640,7 @@ class StreamTaskResponser(TaskResponseProcessor):
601
640
  else:
602
641
  logging.error(
603
642
  f"Failed to save tool result for index {tool_idx}, not yielding result message.")
604
- self.trace.event(name="failed_to_save_tool_result_for_index", level="ERROR",
643
+ langfuse.create_event(trace_context=self.trace_context, name="failed_to_save_tool_result_for_index", level="ERROR",
605
644
  status_message=(
606
645
  f"Failed to save tool result for index {tool_idx}, not yielding result message."))
607
646
  # Optionally yield error status for saving failure?
@@ -609,7 +648,7 @@ class StreamTaskResponser(TaskResponseProcessor):
609
648
  # --- Final Finish Status ---
610
649
  if finish_reason and finish_reason != "xml_tool_limit_reached":
611
650
  finish_content = {"status_type": "finish", "finish_reason": finish_reason}
612
- finish_msg_obj = await self.add_message(
651
+ finish_msg_obj = await self.add_response_message(
613
652
  type="status", content=finish_content,
614
653
  is_llm_message=False, metadata={"thread_run_id": thread_run_id}
615
654
  )
@@ -619,7 +658,7 @@ class StreamTaskResponser(TaskResponseProcessor):
619
658
  if agent_should_terminate:
620
659
  logging.info(
621
660
  "Agent termination requested after executing ask/complete tool. Stopping further processing.")
622
- self.trace.event(name="agent_termination_requested", level="DEFAULT",
661
+ langfuse.create_event(trace_context=self.trace_context, name="agent_termination_requested", level="DEFAULT",
623
662
  status_message="Agent termination requested after executing ask/complete tool. Stopping further processing.")
624
663
 
625
664
  # Set finish reason to indicate termination
@@ -627,7 +666,7 @@ class StreamTaskResponser(TaskResponseProcessor):
627
666
 
628
667
  # Save and yield termination status
629
668
  finish_content = {"status_type": "finish", "finish_reason": "agent_terminated"}
630
- finish_msg_obj = await self.add_message(
669
+ finish_msg_obj = await self.add_response_message(
631
670
  type="status", content=finish_content,
632
671
  is_llm_message=False, metadata={"thread_run_id": thread_run_id}
633
672
  )
@@ -671,7 +710,7 @@ class StreamTaskResponser(TaskResponseProcessor):
671
710
  if streaming_metadata.get("response_ms"):
672
711
  assistant_end_content["response_ms"] = streaming_metadata["response_ms"]
673
712
 
674
- await self.add_message(
713
+ await self.add_response_message(
675
714
  type="assistant_response_end",
676
715
  content=assistant_end_content,
677
716
  is_llm_message=False,
@@ -680,7 +719,7 @@ class StreamTaskResponser(TaskResponseProcessor):
680
719
  logging.info("Assistant response end saved for stream (before termination)")
681
720
  except Exception as e:
682
721
  logging.error(f"Error saving assistant response end for stream (before termination): {str(e)}")
683
- self.trace.event(name="error_saving_assistant_response_end_for_stream_before_termination",
722
+ langfuse.create_event(trace_context=self.trace_context, name="error_saving_assistant_response_end_for_stream_before_termination",
684
723
  level="ERROR", status_message=(
685
724
  f"Error saving assistant response end for stream (before termination): {str(e)}"))
686
725
 
@@ -727,7 +766,7 @@ class StreamTaskResponser(TaskResponseProcessor):
727
766
  if streaming_metadata.get("response_ms"):
728
767
  assistant_end_content["response_ms"] = streaming_metadata["response_ms"]
729
768
 
730
- await self.add_message(
769
+ await self.add_response_message(
731
770
  type="assistant_response_end",
732
771
  content=assistant_end_content,
733
772
  is_llm_message=False,
@@ -736,18 +775,18 @@ class StreamTaskResponser(TaskResponseProcessor):
736
775
  logging.info("Assistant response end saved for stream")
737
776
  except Exception as e:
738
777
  logging.error(f"Error saving assistant response end for stream: {str(e)}")
739
- self.trace.event(name="error_saving_assistant_response_end_for_stream", level="ERROR",
778
+ langfuse.create_event(trace_context=self.trace_context, name="error_saving_assistant_response_end_for_stream", level="ERROR",
740
779
  status_message=(f"Error saving assistant response end for stream: {str(e)}"))
741
780
 
742
781
  except Exception as e:
743
782
  logging.error(f"Error processing stream: {str(e)}", exc_info=True)
744
- self.trace.event(name="error_processing_stream", level="ERROR",
783
+ langfuse.create_event(trace_context=self.trace_context, name="error_processing_stream", level="ERROR",
745
784
  status_message=(f"Error processing stream: {str(e)}"))
746
785
  # Save and yield error status message
747
786
 
748
787
  err_content = {"role": "system", "status_type": "error", "message": str(e)}
749
788
  if (not "AnthropicException - Overloaded" in str(e)):
750
- err_msg_obj = await self.add_message(
789
+ err_msg_obj = await self.add_response_message(
751
790
  type="status", content=err_content,
752
791
  is_llm_message=False,
753
792
  metadata={"thread_run_id": thread_run_id if 'thread_run_id' in locals() else None}
@@ -755,12 +794,12 @@ class StreamTaskResponser(TaskResponseProcessor):
755
794
  if err_msg_obj: yield format_for_yield(err_msg_obj) # Yield the saved error message
756
795
  # Re-raise the same exception (not a new one) to ensure proper error propagation
757
796
  logging.critical(f"Re-raising error to stop further processing: {str(e)}")
758
- self.trace.event(name="re_raising_error_to_stop_further_processing", level="ERROR",
797
+ langfuse.create_event(trace_context=self.trace_context, name="re_raising_error_to_stop_further_processing", level="ERROR",
759
798
  status_message=(f"Re-raising error to stop further processing: {str(e)}"))
760
799
  else:
761
800
  logging.error(f"AnthropicException - Overloaded detected - Falling back to OpenRouter: {str(e)}",
762
801
  exc_info=True)
763
- self.trace.event(name="anthropic_exception_overloaded_detected", level="ERROR", status_message=(
802
+ langfuse.create_event(trace_context=self.trace_context, name="anthropic_exception_overloaded_detected", level="ERROR", status_message=(
764
803
  f"AnthropicException - Overloaded detected - Falling back to OpenRouter: {str(e)}"))
765
804
  raise # Use bare 'raise' to preserve the original exception with its traceback
766
805
 
@@ -775,7 +814,7 @@ class StreamTaskResponser(TaskResponseProcessor):
775
814
  # Save and Yield the final thread_run_end status (only if not auto-continuing and finish_reason is not 'length')
776
815
  try:
777
816
  end_content = {"status_type": "thread_run_end"}
778
- end_msg_obj = await self.add_message(
817
+ end_msg_obj = await self.add_response_message(
779
818
  type="status", content=end_content,
780
819
  is_llm_message=False,
781
820
  metadata={"thread_run_id": thread_run_id if 'thread_run_id' in locals() else None}
@@ -783,5 +822,5 @@ class StreamTaskResponser(TaskResponseProcessor):
783
822
  if end_msg_obj: yield format_for_yield(end_msg_obj)
784
823
  except Exception as final_e:
785
824
  logging.error(f"Error in finally block: {str(final_e)}", exc_info=True)
786
- self.trace.event(name="error_in_finally_block", level="ERROR",
825
+ langfuse.create_event(trace_context=self.trace_context, name="error_in_finally_block", level="ERROR",
787
826
  status_message=(f"Error in finally block: {str(final_e)}"))