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.
- xgae/engine/{xga_base.py → engine_base.py} +12 -15
- xgae/engine/{xga_mcp_tool_box.py → mcp_tool_box.py} +6 -9
- xgae/engine/{xga_prompt_builder.py → prompt_builder.py} +3 -2
- xgae/engine/responser/non_stream_responser.py +110 -0
- xgae/engine/responser/{xga_responser_base.py → responser_base.py} +103 -228
- xgae/engine/responser/{xga_stream_responser.py → stream_responser.py} +94 -55
- xgae/engine/task_engine.py +360 -0
- xgae/utils/__init__.py +13 -0
- xgae/utils/{utils.py → misc.py} +0 -8
- xgae/utils/setup_env.py +51 -66
- xgae/utils/xml_tool_parser.py +4 -7
- {xgae-0.1.4.dist-info → xgae-0.1.6.dist-info}/METADATA +1 -1
- xgae-0.1.6.dist-info/RECORD +17 -0
- xgae/engine/responser/xga_non_stream_responser.py +0 -213
- xgae/engine/xga_engine.py +0 -278
- xgae-0.1.4.dist-info/RECORD +0 -16
- {xgae-0.1.4.dist-info → xgae-0.1.6.dist-info}/WHEEL +0 -0
|
@@ -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.
|
|
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:
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
387
|
-
context, None
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
584
|
-
|
|
585
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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)}"))
|