xgae 0.1.5__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,23 +2,25 @@
2
2
  import logging
3
3
  import json
4
4
 
5
- from typing import List, Any, Dict, Optional, AsyncGenerator, cast, Union, Literal
5
+ from typing import List, Any, Dict, Optional, AsyncGenerator, Union, Literal
6
6
  from uuid import uuid4
7
7
 
8
- from xgae.engine.responser.xga_responser_base import TaskResponseContext, TaskResponseProcessor, TaskRunContinuousState
9
- from xgae.engine.xga_base import XGAResponseMsg, XGAToolBox, XGATaskResult
8
+ from xgae.engine.responser.responser_base import TaskResponserContext, TaskResponseProcessor, TaskRunContinuousState
9
+ from xgae.engine.engine_base import XGAResponseMsgType, XGAResponseMessage, XGAToolBox, XGATaskResult
10
+
11
+ from xgae.utils import langfuse, handle_error
10
12
  from xgae.utils.llm_client import LLMClient, LLMConfig
11
- from xgae.utils.setup_env import langfuse
12
- from xgae.utils.utils import handle_error
13
13
 
14
- from xga_prompt_builder import XGAPromptBuilder
15
- from xga_mcp_tool_box import XGAMcpToolBox
14
+ from xgae.utils.json_helpers import format_for_yield
15
+ from prompt_builder import XGAPromptBuilder
16
+ from mcp_tool_box import XGAMcpToolBox
16
17
 
17
18
  class XGATaskEngine:
18
19
  def __init__(self,
19
20
  session_id: Optional[str] = None,
20
21
  task_id: Optional[str] = None,
21
22
  agent_id: Optional[str] = None,
23
+ trace_id: Optional[str] = None,
22
24
  system_prompt: Optional[str] = None,
23
25
  llm_config: Optional[LLMConfig] = None,
24
26
  prompt_builder: Optional[XGAPromptBuilder] = None,
@@ -34,10 +36,10 @@ class XGATaskEngine:
34
36
  self.prompt_builder = prompt_builder or XGAPromptBuilder(system_prompt)
35
37
  self.tool_box = tool_box or XGAMcpToolBox()
36
38
 
37
- self.task_response_msgs: List[XGAResponseMsg] = []
39
+ self.task_response_msgs: List[XGAResponseMessage] = []
38
40
  self.task_no = -1
39
41
  self.task_run_id = f"{self.task_id}[{self.task_no}]"
40
- self.trace_id = None
42
+ self.trace_id :str = trace_id or langfuse.create_trace_id()
41
43
 
42
44
  async def _post_init_(self, general_tools:List[str], custom_tools: List[str]) -> None:
43
45
  await self.tool_box.load_mcp_tools_schema()
@@ -52,6 +54,7 @@ class XGATaskEngine:
52
54
  session_id: Optional[str] = None,
53
55
  task_id: Optional[str] = None,
54
56
  agent_id: Optional[str] = None,
57
+ trace_id: Optional[str] = None,
55
58
  system_prompt: Optional[str] = None,
56
59
  general_tools: Optional[List[str]] = None,
57
60
  custom_tools: Optional[List[str]] = None,
@@ -61,12 +64,19 @@ class XGATaskEngine:
61
64
  engine: XGATaskEngine = cls(session_id=session_id,
62
65
  task_id=task_id,
63
66
  agent_id=agent_id,
67
+ trace_id=trace_id,
64
68
  system_prompt=system_prompt,
65
69
  llm_config=llm_config,
66
70
  prompt_builder=prompt_builder,
67
71
  tool_box=tool_box)
68
72
 
69
73
  general_tools = general_tools or ["complete", "ask"]
74
+ if "*" not in general_tools:
75
+ if "complete" not in general_tools:
76
+ general_tools.append("complete")
77
+ elif "ask" not in general_tools:
78
+ general_tools.append("ask")
79
+
70
80
  custom_tools = custom_tools or []
71
81
  await engine._post_init_(general_tools, custom_tools)
72
82
 
@@ -83,8 +93,10 @@ class XGATaskEngine:
83
93
  chunks = []
84
94
  async for chunk in self.run_task(task_message=task_message, max_auto_run=max_auto_run, trace_id=trace_id):
85
95
  chunks.append(chunk)
86
-
87
- final_result = self._parse_final_result(chunks)
96
+ if len(chunks) > 0:
97
+ final_result = self._parse_final_result(chunks)
98
+ else:
99
+ final_result = XGATaskResult(type="error", content="LLM Answer is Empty")
88
100
  return final_result
89
101
 
90
102
  async def run_task(self,
@@ -97,25 +109,22 @@ class XGATaskEngine:
97
109
  self.task_no += 1
98
110
  self.task_run_id = f"{self.task_id}[{self.task_no}]"
99
111
 
100
- self.add_response_msg(type="user", content=task_message, is_llm_message=True)
112
+ self.add_response_message(type="user", content=task_message, is_llm_message=True)
101
113
 
102
- if max_auto_run <= 1:
103
- continuous_state:TaskRunContinuousState = {
104
- "accumulated_content": "",
105
- "auto_continue_count": 0,
106
- "auto_continue": False
107
- }
108
- async for chunk in self._run_task_once(continuous_state):
109
- yield chunk
110
- else:
111
- async for chunk in self._run_task_auto(max_auto_run):
112
- yield chunk
114
+ continuous_state: TaskRunContinuousState = {
115
+ "accumulated_content": "",
116
+ "auto_continue_count": 0,
117
+ "auto_continue": False if max_auto_run <= 1 else True,
118
+ "max_auto_run": max_auto_run
119
+ }
120
+ async for chunk in self._run_task_auto(continuous_state):
121
+ yield chunk
113
122
  finally:
114
123
  await self.tool_box.destroy_task_tool_box(self.task_id)
115
124
 
116
125
  async def _run_task_once(self, continuous_state: TaskRunContinuousState) -> AsyncGenerator[Dict[str, Any], None]:
117
126
  llm_messages = [{"role": "system", "content": self.task_prompt}]
118
- cxt_llm_contents = self._get_response_llm_contents()
127
+ cxt_llm_contents = self.get_history_llm_messages()
119
128
  llm_messages.extend(cxt_llm_contents)
120
129
 
121
130
  partial_content = continuous_state.get('accumulated_content', '')
@@ -130,15 +139,12 @@ class XGATaskEngine:
130
139
  response_processor = self._create_response_processer()
131
140
 
132
141
  async for chunk in response_processor.process_response(llm_response, llm_messages, continuous_state):
133
- self._reponse_chunk_log(chunk)
142
+ self._logging_reponse_chunk(chunk)
134
143
  yield chunk
135
144
 
136
- async def _run_task_auto(self, max_auto_run: int) -> AsyncGenerator[Dict[str, Any], None]:
137
- continuous_state: TaskRunContinuousState = {
138
- "accumulated_content": "",
139
- "auto_continue_count": 0,
140
- "auto_continue": True
141
- }
145
+ async def _run_task_auto(self, continuous_state: TaskRunContinuousState) -> AsyncGenerator[Dict[str, Any], None]:
146
+ max_auto_run = continuous_state['max_auto_run']
147
+ max_auto_run = max_auto_run if max_auto_run > 0 else 1
142
148
 
143
149
  def update_continuous_state(_auto_continue_count, _auto_continue):
144
150
  continuous_state["auto_continue_count"] = _auto_continue_count
@@ -163,11 +169,11 @@ class XGATaskEngine:
163
169
  elif status_type == 'finish':
164
170
  finish_reason = content.get('finish_reason', None)
165
171
  if finish_reason == 'completed':
166
- logging.warning(f"run_task_auto: Detected finish_reason='completed', Task Completed Success !")
172
+ logging.info(f"run_task_auto: Detected finish_reason='completed', TASK_COMPLETE Success !")
167
173
  auto_continue = False
168
174
  break
169
175
  elif finish_reason == 'xml_tool_limit_reached':
170
- logging.warning(f"run_task_auto: Detected finish_reason='xml_tool_limit_reached', stopping auto-continue")
176
+ logging.warning(f"run_task_auto: Detected finish_reason='xml_tool_limit_reached', stop auto-continue")
171
177
  auto_continue = False
172
178
  break
173
179
  elif finish_reason == 'stop' or finish_reason == 'length': # 'length' never occur
@@ -175,18 +181,18 @@ class XGATaskEngine:
175
181
  auto_continue_count += 1
176
182
  update_continuous_state(auto_continue_count, auto_continue)
177
183
  logging.info(f"run_task_auto: Detected finish_reason='{finish_reason}', auto-continuing ({auto_continue_count}/{max_auto_run})")
178
- except StopAsyncIteration:
179
- pass
180
184
  except Exception as parse_error:
181
185
  logging.error(f"run_task_auto: Error in parse chunk: {str(parse_error)}")
182
186
  content = {"role": "system", "status_type": "error", "message": "Parse response chunk Error"}
183
- error_msg = self.add_response_msg(type="status", content=content, is_llm_message=False)
184
- yield error_msg
187
+ handle_error(parse_error)
188
+ error_msg = self.add_response_message(type="status", content=content, is_llm_message=False)
189
+ yield format_for_yield(error_msg)
185
190
  except Exception as run_error:
186
191
  logging.error(f"run_task_auto: Call task_run_once error: {str(run_error)}")
187
192
  content = {"role": "system", "status_type": "error", "message": "Call task_run_once error"}
188
- error_msg = self.add_response_msg(type="status", content=content, is_llm_message=False)
189
- yield error_msg
193
+ handle_error(run_error)
194
+ error_msg = self.add_response_message(type="status", content=content, is_llm_message=False)
195
+ yield format_for_yield(error_msg)
190
196
 
191
197
  def _parse_final_result(self, chunks: List[Dict[str, Any]]) -> XGATaskResult:
192
198
  final_result: XGATaskResult = None
@@ -200,14 +206,11 @@ class XGATaskEngine:
200
206
  if status_type == "error":
201
207
  error = status_content.get('message', 'Unknown error')
202
208
  final_result = XGATaskResult(type="error", content=error)
203
- break
204
209
  elif status_type == "finish":
205
210
  finish_reason = status_content.get('finish_reason', None)
206
211
  if finish_reason == 'xml_tool_limit_reached':
207
212
  error = "Completed due to over task max_auto_run limit !"
208
213
  final_result = XGATaskResult(type="error", content=error)
209
- break
210
- continue
211
214
  elif chunk_type == "tool" and finish_reason in ['completed', 'stop']:
212
215
  tool_content = json.loads(chunk.get('content', '{}'))
213
216
  tool_execution = tool_content.get('tool_execution')
@@ -229,9 +232,10 @@ class XGATaskEngine:
229
232
  result_content = f"Task execute '{tool_name}' {result_type}: {output}"
230
233
  final_result = XGATaskResult(type=result_type, content=result_content)
231
234
  elif chunk_type == "assistant" and finish_reason == 'stop':
232
- assis_content = chunk.get('content', '{}')
235
+ assis_content = chunk.get('content', {})
233
236
  result_content = assis_content.get("content", "LLM output is empty")
234
237
  final_result = XGATaskResult(type="answer", content=result_content)
238
+
235
239
  if final_result is not None:
236
240
  break
237
241
  except Exception as e:
@@ -241,74 +245,77 @@ class XGATaskEngine:
241
245
 
242
246
  return final_result
243
247
 
244
- def add_response_msg(self, type: Literal["user", "status", "tool", "assistant", "assistant_response_end"],
245
- content: Union[Dict[str, Any], List[Any], str],
246
- is_llm_message: bool,
247
- metadata: Optional[Dict[str, Any]]=None)-> XGAResponseMsg:
248
- message = XGAResponseMsg(
248
+ def add_response_message(self, type: XGAResponseMsgType,
249
+ content: Union[Dict[str, Any], List[Any], str],
250
+ is_llm_message: bool,
251
+ metadata: Optional[Dict[str, Any]]=None)-> XGAResponseMessage:
252
+ metadata = metadata or {}
253
+ metadata["task_id"] = self.task_id
254
+ metadata["task_run_id"] = self.task_run_id
255
+ metadata["trace_id"] = self.trace_id
256
+ metadata["session_id"] = self.session_id
257
+ metadata["agent_id"] = self.agent_id
258
+
259
+ message = XGAResponseMessage(
249
260
  message_id = f"xga_msg_{uuid4()}",
250
261
  type = type,
251
- content = content,
252
262
  is_llm_message=is_llm_message,
253
- metadata = metadata,
254
- session_id = self.session_id,
255
- agent_id = self.agent_id,
256
- task_id = self.task_id,
257
- task_run_id = self.task_run_id,
258
- trace_id = self.trace_id
263
+ content = content,
264
+ metadata = metadata
259
265
  )
260
266
  self.task_response_msgs.append(message)
261
267
 
262
268
  return message
263
269
 
264
- def _get_response_llm_contents (self) -> List[Dict[str, Any]]:
270
+ def get_history_llm_messages (self) -> List[Dict[str, Any]]:
265
271
  llm_messages = []
266
272
  for message in self.task_response_msgs:
267
273
  if message["is_llm_message"]:
268
274
  llm_messages.append(message)
269
275
 
270
- cxt_llm_contents = []
276
+ response_llm_contents = []
271
277
  for llm_message in llm_messages:
272
278
  content = llm_message["content"]
273
279
  # @todo content List type
274
280
  if isinstance(content, str):
275
281
  try:
276
282
  _content = json.loads(content)
277
- cxt_llm_contents.append(_content)
283
+ response_llm_contents.append(_content)
278
284
  except json.JSONDecodeError as e:
279
285
  logging.error(f"get_context_llm_contents: Failed to decode json, content=:{content}")
280
286
  handle_error(e)
281
287
  else:
282
- cxt_llm_contents.append(content)
288
+ response_llm_contents.append(content)
283
289
 
284
- return cxt_llm_contents
290
+ return response_llm_contents
285
291
 
286
292
  def _create_response_processer(self) -> TaskResponseProcessor:
287
293
  response_context = self._create_response_context()
288
294
  is_stream = response_context.get("is_stream", False)
289
295
  if is_stream:
290
- from xgae.engine.responser.xga_stream_responser import StreamTaskResponser
296
+ from xgae.engine.responser.stream_responser import StreamTaskResponser
291
297
  return StreamTaskResponser(response_context)
292
298
  else:
293
- from xgae.engine.responser.xga_non_stream_responser import NonStreamTaskResponser
299
+ from xgae.engine.responser.non_stream_responser import NonStreamTaskResponser
294
300
  return NonStreamTaskResponser(response_context)
295
301
 
296
- def _create_response_context(self) -> TaskResponseContext:
297
- response_context: TaskResponseContext = {
302
+ def _create_response_context(self) -> TaskResponserContext:
303
+ response_context: TaskResponserContext = {
298
304
  "is_stream": self.is_stream,
299
305
  "task_id": self.task_id,
300
306
  "task_run_id": self.task_run_id,
301
307
  "trace_id": self.trace_id,
302
308
  "model_name": self.model_name,
303
309
  "max_xml_tool_calls": 0,
304
- "add_context_msg": self.add_response_msg,
310
+ "add_response_msg_func": self.add_response_message,
305
311
  "tool_box": self.tool_box,
306
- "tool_execution_strategy": "parallel",
312
+ "tool_execution_strategy": "sequential" ,#"parallel",
307
313
  "xml_adding_strategy": "user_message",
308
314
  }
309
315
  return response_context
310
316
 
311
- def _reponse_chunk_log(self, chunk):
317
+
318
+ def _logging_reponse_chunk(self, chunk):
312
319
  chunk_type = chunk.get('type')
313
320
  prefix = ""
314
321
 
@@ -327,7 +334,8 @@ class XGATaskEngine:
327
334
 
328
335
  if __name__ == "__main__":
329
336
  import asyncio
330
- from xgae.utils.utils import read_file
337
+ from xgae.utils.misc import read_file
338
+
331
339
  async def main():
332
340
  tool_box = XGAMcpToolBox(custom_mcp_server_file="mcpservers/custom_servers.json")
333
341
  system_prompt = read_file("templates/scp_test_prompt.txt")
@@ -336,12 +344,17 @@ if __name__ == "__main__":
336
344
  custom_tools=["bomc_fault.*"],
337
345
  llm_config=LLMConfig(stream=False),
338
346
  system_prompt=system_prompt)
339
- # engine = await XGATaskEngine.create(llm_config=LLMConfig(stream=False))
340
- #chunks = []
341
- # async for chunk in engine.run_task(task_message={"role": "user", "content": "定位10.0.0.1的故障"},max_auto_run=8):
342
- # print(chunk)
343
- #final_result = await engine.run_task_with_final_answer(task_message={"role": "user", "content": "1+1"}, max_auto_run=2)
344
347
 
345
348
  final_result = await engine.run_task_with_final_answer(task_message={"role": "user", "content": "定位10.0.1.1故障"},max_auto_run=8)
346
349
  print("FINAL RESULT:", final_result)
350
+
351
+ # ==== test streaming response ========
352
+ #chunks = []
353
+ # async for chunk in engine.run_task(task_message={"role": "user", "content": "定位10.0.0.1的故障"}, max_auto_run=8):
354
+ # print(chunk)
355
+
356
+ # ==== test no tool call ========
357
+ # engine = await XGATaskEngine.create(llm_config=LLMConfig(stream=False))
358
+ # final_result = await engine.run_task_with_final_answer(task_message={"role": "user", "content": "1+1"}, max_auto_run=2)
359
+ # print("FINAL RESULT:", final_result)
347
360
  asyncio.run(main())
xgae/utils/__init__.py ADDED
@@ -0,0 +1,13 @@
1
+ import logging
2
+
3
+ from .setup_env import setup_langfuse, setup_logging
4
+
5
+ setup_logging()
6
+ langfuse = setup_langfuse()
7
+
8
+ def handle_error(e: Exception) -> None:
9
+ import traceback
10
+
11
+ logging.error("An error occurred: %s", str(e))
12
+ logging.error("Traceback details:\n%s", traceback.format_exc())
13
+ raise (e) from e
@@ -1,17 +1,9 @@
1
1
  import logging
2
2
  import os
3
3
  import sys
4
- import datetime
5
4
 
6
5
  from typing import Any, Dict
7
6
 
8
- def handle_error(e: Exception) -> None:
9
- import traceback
10
-
11
- logging.error("An error occurred: %s", str(e))
12
- logging.error("Traceback details:\n%s", traceback.format_exc())
13
- raise (e) from e
14
-
15
7
  def read_file(file_path: str) -> str:
16
8
  if not os.path.exists(file_path):
17
9
  logging.error(f"File '{file_path}' not found")
xgae/utils/setup_env.py CHANGED
@@ -3,91 +3,76 @@ import os
3
3
 
4
4
  from langfuse import Langfuse
5
5
 
6
- _log_initialized = False
7
-
8
6
  def setup_logging() -> None:
9
- global _log_initialized
10
- if not _log_initialized:
11
- import colorlog
12
- from dotenv import load_dotenv
13
- load_dotenv()
14
-
15
- env_log_level = os.getenv("LOG_LEVEL", "INFO")
16
- env_log_file = os.getenv("LOG_FILE", "log/xga.log")
17
- log_level = getattr(logging, env_log_level.upper(), logging.INFO)
18
-
19
- log_dir = os.path.dirname(env_log_file)
20
- if log_dir and not os.path.exists(log_dir):
21
- os.makedirs(log_dir, exist_ok=True)
22
- else:
23
- os.remove(env_log_file)
24
-
25
- logger = logging.getLogger()
26
- for handler in logger.handlers[:]:
27
- logger.removeHandler(handler)
7
+ import colorlog
8
+ from dotenv import load_dotenv
9
+ load_dotenv()
28
10
 
11
+ env_log_level = os.getenv("LOG_LEVEL", "INFO")
12
+ env_log_file = os.getenv("LOG_FILE", "log/xga.log")
13
+ log_level = getattr(logging, env_log_level.upper(), logging.INFO)
29
14
 
15
+ log_dir = os.path.dirname(env_log_file)
16
+ if log_dir and not os.path.exists(log_dir):
17
+ os.makedirs(log_dir, exist_ok=True)
18
+ else:
19
+ os.remove(env_log_file)
30
20
 
31
- log_colors = {
32
- 'DEBUG': 'cyan',
33
- 'INFO': 'green',
34
- 'WARNING': 'yellow',
35
- 'ERROR': 'red',
36
- 'CRITICAL': 'red,bg_white'
37
- }
21
+ logger = logging.getLogger()
22
+ for handler in logger.handlers[:]:
23
+ logger.removeHandler(handler)
38
24
 
39
- console_formatter = colorlog.ColoredFormatter('%(log_color)s%(asctime)s - %(levelname)-8s%(reset)s %(white)s%(message)s',
40
- log_colors=log_colors,
41
- datefmt='%Y-%m-%d %H:%M:%S'
42
- )
25
+ log_colors = {
26
+ 'DEBUG': 'cyan',
27
+ 'INFO': 'green',
28
+ 'WARNING': 'yellow',
29
+ 'ERROR': 'red',
30
+ 'CRITICAL': 'red,bg_white'
31
+ }
43
32
 
44
- file_formatter = logging.Formatter(
45
- '%(asctime)s -%(levelname)-8s %(message)s',
46
- datefmt='%Y-%m-%d %H:%M:%S'
47
- )
33
+ console_formatter = colorlog.ColoredFormatter('%(log_color)s%(asctime)s - %(levelname)-8s%(reset)s %(white)s%(message)s',
34
+ log_colors=log_colors,
35
+ datefmt='%Y-%m-%d %H:%M:%S'
36
+ )
48
37
 
49
- console_handler = logging.StreamHandler()
50
- console_handler.setFormatter(console_formatter)
38
+ file_formatter = logging.Formatter(
39
+ '%(asctime)s -%(levelname)-8s %(message)s',
40
+ datefmt='%Y-%m-%d %H:%M:%S'
41
+ )
51
42
 
52
- file_handler = logging.FileHandler(env_log_file, encoding='utf-8')
53
- file_handler.setFormatter(file_formatter)
43
+ console_handler = logging.StreamHandler()
44
+ console_handler.setFormatter(console_formatter)
54
45
 
55
- logger.addHandler(console_handler)
56
- logger.addHandler(file_handler)
46
+ file_handler = logging.FileHandler(env_log_file, encoding='utf-8')
47
+ file_handler.setFormatter(file_formatter)
57
48
 
58
- logger.setLevel(log_level)
49
+ logger.addHandler(console_handler)
50
+ logger.addHandler(file_handler)
59
51
 
60
- logging.info(f"Logger is initialized, log_level={env_log_level}, log_file={env_log_file}")
52
+ logger.setLevel(log_level)
61
53
 
62
- _log_initialized = True
54
+ logging.info(f"Logger is initialized, log_level={env_log_level}, log_file={env_log_file}")
63
55
 
64
- setup_logging()
65
-
66
- _langfuse_initialized = False
67
56
 
68
57
  def setup_langfuse() -> Langfuse:
69
- global _langfuse_initialized
70
58
  _langfuse = None
71
- if not _langfuse_initialized:
72
- env_public_key = os.getenv("LANGFUSE_PUBLIC_KEY")
73
- env_secret_key = os.getenv("LANGFUSE_SECRET_KEY")
74
- env_host = os.getenv("LANGFUSE_HOST", "https://cloud.langfuse.com")
75
- if env_public_key and env_secret_key:
76
- _langfuse = Langfuse(tracing_enabled=True,
77
- public_key=env_public_key,
78
- secret_key=env_secret_key,
79
- host=env_host)
80
- logging.info("Langfuse initialized Successfully by Key !")
81
- else:
82
- _langfuse = Langfuse(tracing_enabled=False)
83
- logging.warning("Not set key, Langfuse is disabled!")
84
-
85
- _langfuse_initialized = True
86
- return _langfuse
59
+ env_public_key = os.getenv("LANGFUSE_PUBLIC_KEY")
60
+ env_secret_key = os.getenv("LANGFUSE_SECRET_KEY")
61
+ env_host = os.getenv("LANGFUSE_HOST", "https://cloud.langfuse.com")
62
+ if env_public_key and env_secret_key:
63
+ _langfuse = Langfuse(tracing_enabled=True,
64
+ public_key=env_public_key,
65
+ secret_key=env_secret_key,
66
+ host=env_host)
67
+ logging.info("Langfuse initialized Successfully by Key !")
68
+ else:
69
+ _langfuse = Langfuse(tracing_enabled=False)
70
+ logging.warning("Not set key, Langfuse is disabled!")
87
71
 
88
- langfuse: Langfuse = Langfuse if _langfuse_initialized else setup_langfuse()
72
+ return _langfuse
89
73
 
90
74
 
91
75
  if __name__ == "__main__":
76
+ from xgae.utils import langfuse
92
77
  trace_id = langfuse.create_trace_id()
93
78
  logging.warning(f"trace_id={trace_id}")
@@ -5,14 +5,11 @@ This module provides a reliable XML tool call parsing system that supports
5
5
  the XML format with structured function_calls blocks.
6
6
  """
7
7
 
8
- import re
9
- import xml.etree.ElementTree as ET
10
- from typing import List, Dict, Any, Optional, Tuple
11
- from dataclasses import dataclass
12
8
  import json
13
9
  import logging
14
-
15
- logger = logging.getLogger(__name__)
10
+ import re
11
+ from dataclasses import dataclass
12
+ from typing import List, Dict, Any, Optional, Tuple
16
13
 
17
14
 
18
15
  @dataclass
@@ -85,7 +82,7 @@ class XMLToolParser:
85
82
  if tool_call:
86
83
  tool_calls.append(tool_call)
87
84
  except Exception as e:
88
- logger.error(f"Error parsing invoke block for {function_name}: {e}")
85
+ logging.error(f"Error parsing invoke block for {function_name}: {e}")
89
86
 
90
87
  return tool_calls
91
88
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xgae
3
- Version: 0.1.5
3
+ Version: 0.1.6
4
4
  Summary: Extreme General Agent Engine
5
5
  Requires-Python: >=3.13
6
6
  Requires-Dist: colorlog>=6.9.0
@@ -0,0 +1,17 @@
1
+ xgae/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ xgae/engine/engine_base.py,sha256=ySERuLy1YWsf-3s0NFKcyTnXQ4g69wR-cQhtnG0OFmU,1747
3
+ xgae/engine/mcp_tool_box.py,sha256=6mdvu9-aquyLJEwebTtpa_bfGmgT1jPszKE90NIpR5c,9852
4
+ xgae/engine/prompt_builder.py,sha256=ygFAIc4p3opIMyl6g1JeBuSiMjNVxwRloKeF2eX8R5I,4354
5
+ xgae/engine/task_engine.py,sha256=xxAWtPfKgSpf6L7wOc243U-7YP8AC2WYoCI-FUdDpOc,18132
6
+ xgae/engine/responser/non_stream_responser.py,sha256=QEFE4JGYVaIbFeMUMJa1Mt1uBblU_hAOywAhyp9V1k4,6634
7
+ xgae/engine/responser/responser_base.py,sha256=aHKJ880B1ezfBWzyHoOSNVDb-CJY4ujH2MGm61aJLy8,31468
8
+ xgae/engine/responser/stream_responser.py,sha256=5KzCHApiPplZ-zN_sbbEbSvj2rtvKWBshJKe_-x7RDI,52927
9
+ xgae/utils/__init__.py,sha256=jChvD-p_p5gsrCZUVYPUGJs4CS9gIdNFcSOpkRpcM4Y,317
10
+ xgae/utils/json_helpers.py,sha256=K1ja6GJCatrAheW9bEWAYSQbDI42__boBCZgtsv1gtk,4865
11
+ xgae/utils/llm_client.py,sha256=mgzn8heUyRm92HTLEYGdfsGEpFtD-xLFr39P98_JP0s,12402
12
+ xgae/utils/misc.py,sha256=EK94YesZp8AmRUqWfN-CjTxyEHPWdIIWpFNO17dzm9g,915
13
+ xgae/utils/setup_env.py,sha256=Nc0HCQOnK-EGNLTWCQ9-iYysNRdIvwGhcHdqpNeV910,2407
14
+ xgae/utils/xml_tool_parser.py,sha256=EJ6BjpD4CSdmS_LqViUJ6P8H9GY2R1e4Dh8rLCR6nSE,7474
15
+ xgae-0.1.6.dist-info/METADATA,sha256=Q5OiPe5W3H7ym2TDPaM1x3k6jSTIol3QDyWI0dsQetw,309
16
+ xgae-0.1.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
17
+ xgae-0.1.6.dist-info/RECORD,,