xgae 0.1.18__py3-none-any.whl → 0.1.19__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/__init__.py +1 -1
- xgae/engine/task_engine.py +37 -27
- xgae/engine/task_langfuse.py +19 -7
- xgae/{cli_app.py → engine_cli_app.py} +16 -19
- {xgae-0.1.18.dist-info → xgae-0.1.19.dist-info}/METADATA +2 -1
- {xgae-0.1.18.dist-info → xgae-0.1.19.dist-info}/RECORD +8 -8
- {xgae-0.1.18.dist-info → xgae-0.1.19.dist-info}/entry_points.txt +1 -1
- {xgae-0.1.18.dist-info → xgae-0.1.19.dist-info}/WHEEL +0 -0
xgae/__init__.py
CHANGED
xgae/engine/task_engine.py
CHANGED
|
@@ -17,8 +17,9 @@ from xgae.engine.responser.responser_base import TaskResponserContext, TaskRespo
|
|
|
17
17
|
|
|
18
18
|
class XGATaskEngine:
|
|
19
19
|
def __init__(self,
|
|
20
|
-
session_id: Optional[str] = None,
|
|
21
20
|
task_id: Optional[str] = None,
|
|
21
|
+
session_id: Optional[str] = None,
|
|
22
|
+
user_id: Optional[str] = None,
|
|
22
23
|
agent_id: Optional[str] = None,
|
|
23
24
|
general_tools: Optional[List[str]] = None,
|
|
24
25
|
custom_tools: Optional[List[str]] = None,
|
|
@@ -29,8 +30,9 @@ class XGATaskEngine:
|
|
|
29
30
|
prompt_builder: Optional[XGAPromptBuilder] = None,
|
|
30
31
|
tool_box: Optional[XGAToolBox] = None):
|
|
31
32
|
self.task_id = task_id if task_id else f"xga_task_{uuid4()}"
|
|
32
|
-
self.agent_id = agent_id
|
|
33
33
|
self.session_id = session_id
|
|
34
|
+
self.user_id = user_id
|
|
35
|
+
self.agent_id = agent_id
|
|
34
36
|
|
|
35
37
|
self.llm_client = LLMClient(llm_config)
|
|
36
38
|
self.model_name = self.llm_client.model_name
|
|
@@ -56,16 +58,16 @@ class XGATaskEngine:
|
|
|
56
58
|
self.task_response_msgs: List[XGAResponseMessage] = []
|
|
57
59
|
|
|
58
60
|
async def run_task_with_final_answer(self,
|
|
59
|
-
|
|
61
|
+
task_input: Dict[str, Any],
|
|
60
62
|
trace_id: Optional[str] = None) -> XGATaskResult:
|
|
61
|
-
final_result:XGATaskResult = None
|
|
63
|
+
final_result: XGATaskResult = None
|
|
62
64
|
try:
|
|
63
65
|
await self._init_task()
|
|
64
66
|
|
|
65
|
-
self.task_langfuse.start_root_span("run_task_with_final_answer",
|
|
67
|
+
self.task_langfuse.start_root_span("run_task_with_final_answer", task_input, trace_id)
|
|
66
68
|
|
|
67
69
|
chunks = []
|
|
68
|
-
async for chunk in self.run_task(
|
|
70
|
+
async for chunk in self.run_task(task_input, trace_id):
|
|
69
71
|
chunks.append(chunk)
|
|
70
72
|
|
|
71
73
|
if len(chunks) > 0:
|
|
@@ -79,14 +81,14 @@ class XGATaskEngine:
|
|
|
79
81
|
|
|
80
82
|
|
|
81
83
|
async def run_task(self,
|
|
82
|
-
|
|
84
|
+
task_input: Dict[str, Any],
|
|
83
85
|
trace_id: Optional[str] = None) -> AsyncGenerator[Dict[str, Any], None]:
|
|
84
86
|
try:
|
|
85
87
|
await self._init_task()
|
|
86
88
|
|
|
87
|
-
self.task_langfuse.start_root_span("run_task",
|
|
89
|
+
self.task_langfuse.start_root_span("run_task", task_input, trace_id)
|
|
88
90
|
|
|
89
|
-
self.add_response_message(type="user", content=
|
|
91
|
+
self.add_response_message(type="user", content=task_input, is_llm_message=True)
|
|
90
92
|
|
|
91
93
|
async for chunk in self._run_task_auto():
|
|
92
94
|
yield chunk
|
|
@@ -153,30 +155,30 @@ class XGATaskEngine:
|
|
|
153
155
|
status_content = chunk['content']
|
|
154
156
|
status_type = status_content['status_type']
|
|
155
157
|
if status_type == "error":
|
|
156
|
-
logging.error(f"
|
|
158
|
+
logging.error(f"XGATaskEngine run_task_auto: task_response error: {chunk.get('message')}")
|
|
157
159
|
auto_continue = False
|
|
158
160
|
break
|
|
159
161
|
elif status_type == "finish":
|
|
160
162
|
finish_reason = status_content['finish_reason']
|
|
161
163
|
if finish_reason == "completed":
|
|
162
|
-
logging.info(f"
|
|
164
|
+
logging.info(f"XGATaskEngine run_task_auto: Detected finish_reason='completed', TASK_COMPLETE Success !")
|
|
163
165
|
auto_continue = False
|
|
164
166
|
break
|
|
165
167
|
elif finish_reason == "xml_tool_limit_reached":
|
|
166
|
-
logging.warning(f"
|
|
168
|
+
logging.warning(f"XGATaskEngine run_task_auto: Detected finish_reason='xml_tool_limit_reached', stop auto-continue")
|
|
167
169
|
auto_continue = False
|
|
168
170
|
break
|
|
169
171
|
elif finish_reason == "non_tool_call":
|
|
170
|
-
logging.warning(f"
|
|
172
|
+
logging.warning(f"XGATaskEngine run_task_auto: Detected finish_reason='non_tool_call', stop auto-continue")
|
|
171
173
|
auto_continue = False
|
|
172
174
|
break
|
|
173
175
|
elif finish_reason in ["stop", "length"]: # 'length' occur on some LLM
|
|
174
176
|
auto_continue_count += 1
|
|
175
177
|
auto_continue = True if auto_continue_count < self.max_auto_run else False
|
|
176
178
|
update_continuous_state(auto_continue_count, auto_continue)
|
|
177
|
-
logging.info(f"
|
|
179
|
+
logging.info(f"XGATaskEngine run_task_auto: Detected finish_reason='{finish_reason}', auto-continuing ({auto_continue_count}/{self.max_auto_run})")
|
|
178
180
|
except Exception as parse_error:
|
|
179
|
-
trace = log_trace(parse_error,f"
|
|
181
|
+
trace = log_trace(parse_error,f"XGATaskEngine run_task_auto: Parse chunk error, chunk: {chunk}")
|
|
180
182
|
self.task_langfuse.root_span.event(name="engine_parse_chunk_error", level="ERROR",
|
|
181
183
|
status_message=f"Task Engine parse chunk error: {parse_error}",
|
|
182
184
|
metadata={"content": chunk, "trace": trace})
|
|
@@ -185,7 +187,7 @@ class XGATaskEngine:
|
|
|
185
187
|
error_msg = self.add_response_message(type="status", content=status_content, is_llm_message=False)
|
|
186
188
|
yield error_msg
|
|
187
189
|
except Exception as run_error:
|
|
188
|
-
trace = log_trace(run_error, "
|
|
190
|
+
trace = log_trace(run_error, "XGATaskEngine run_task_auto: Call task_run_once")
|
|
189
191
|
self.task_langfuse.root_span.event(name="engine_task_run_once_error", level="ERROR",
|
|
190
192
|
status_message=f"Call task_run_once error: {run_error}",
|
|
191
193
|
metadata={"trace": trace})
|
|
@@ -271,7 +273,7 @@ class XGATaskEngine:
|
|
|
271
273
|
logging.warning(f"❌ FINAL_RESULT: LLM Result is EMPTY, finish_reason={finish_reason}")
|
|
272
274
|
final_result = XGATaskResult(type="error", content="LLM has no answer")
|
|
273
275
|
except Exception as e:
|
|
274
|
-
trace = log_trace(e, f"
|
|
276
|
+
trace = log_trace(e, f"XGATaskEngine parse_final_result: Parse message chunk error, chunk: {chunk}")
|
|
275
277
|
self.task_langfuse.root_span.event(name="engine_parse_final_result_error", level="ERROR",
|
|
276
278
|
status_message=f"Task Engine parse final result error: {e}",
|
|
277
279
|
metadata={"content": chunk, "trace": trace})
|
|
@@ -285,11 +287,12 @@ class XGATaskEngine:
|
|
|
285
287
|
is_llm_message: bool,
|
|
286
288
|
metadata: Optional[Dict[str, Any]]=None)-> XGAResponseMessage:
|
|
287
289
|
metadata = metadata or {}
|
|
288
|
-
metadata[
|
|
289
|
-
metadata[
|
|
290
|
-
metadata[
|
|
291
|
-
metadata[
|
|
292
|
-
metadata[
|
|
290
|
+
metadata['task_id'] = self.task_id
|
|
291
|
+
metadata['task_run_id'] = self.task_run_id
|
|
292
|
+
metadata['trace_id'] = self.task_langfuse.trace_id
|
|
293
|
+
metadata['session_id'] = self.session_id
|
|
294
|
+
metadata['user_id'] = self.user_id
|
|
295
|
+
metadata['agent_id'] = self.agent_id
|
|
293
296
|
|
|
294
297
|
message = XGAResponseMessage(
|
|
295
298
|
message_id = f"xga_msg_{uuid4()}",
|
|
@@ -359,7 +362,14 @@ class XGATaskEngine:
|
|
|
359
362
|
|
|
360
363
|
|
|
361
364
|
def _create_task_langfuse(self)-> XGATaskLangFuse:
|
|
362
|
-
return XGATaskLangFuse(
|
|
365
|
+
return XGATaskLangFuse(
|
|
366
|
+
task_id = self.task_id,
|
|
367
|
+
task_run_id = self.task_run_id,
|
|
368
|
+
task_no = self.task_no,
|
|
369
|
+
session_id = self.session_id,
|
|
370
|
+
agent_id = self.agent_id,
|
|
371
|
+
user_id = self.user_id
|
|
372
|
+
)
|
|
363
373
|
|
|
364
374
|
|
|
365
375
|
def _logging_reponse_chunk(self, chunk, auto_count: int)-> None:
|
|
@@ -384,11 +394,11 @@ class XGATaskEngine:
|
|
|
384
394
|
pretty_content = json.dumps(status_content, ensure_ascii=False, indent=2)
|
|
385
395
|
|
|
386
396
|
if chunk_type == "assistant_chunk":
|
|
387
|
-
logging.debug(f"TASK_RESP_CHUNK[{auto_count}
|
|
397
|
+
logging.debug(f"TASK_RESP_CHUNK[{self.task_no}]({auto_count})<{chunk_type}{prefix}> content: {pretty_content}")
|
|
388
398
|
else:
|
|
389
|
-
logging.info(f"TASK_RESP_CHUNK[{auto_count}
|
|
399
|
+
logging.info(f"TASK_RESP_CHUNK[{self.task_no}]({auto_count})<{chunk_type}{prefix}> content: {pretty_content}")
|
|
390
400
|
except Exception as e:
|
|
391
|
-
logging.error(f"
|
|
401
|
+
logging.error(f"XGATaskEngine logging_reponse_chunk: Decorate chunk={chunk}, error: {e}")
|
|
392
402
|
|
|
393
403
|
|
|
394
404
|
|
|
@@ -410,7 +420,7 @@ if __name__ == "__main__":
|
|
|
410
420
|
agent_id="agent_1"
|
|
411
421
|
)
|
|
412
422
|
user_input = "locate 10.0.0.1 fault and solution"
|
|
413
|
-
final_result = await engine.run_task_with_final_answer(
|
|
423
|
+
final_result = await engine.run_task_with_final_answer(task_input={'role': "user", 'content': user_input})
|
|
414
424
|
print(f"FINAL RESULT:{final_result}")
|
|
415
425
|
|
|
416
426
|
|
xgae/engine/task_langfuse.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import logging
|
|
2
2
|
from typing import Any, Dict, Optional
|
|
3
3
|
from langfuse import Langfuse
|
|
4
4
|
|
|
@@ -10,10 +10,11 @@ class XGATaskLangFuse:
|
|
|
10
10
|
langfuse: Langfuse = None
|
|
11
11
|
|
|
12
12
|
def __init__(self,
|
|
13
|
-
session_id: str,
|
|
14
13
|
task_id:str,
|
|
15
14
|
task_run_id: str,
|
|
16
15
|
task_no: int,
|
|
16
|
+
session_id: str,
|
|
17
|
+
user_id: str,
|
|
17
18
|
agent_id: str) -> None:
|
|
18
19
|
if XGATaskLangFuse.langfuse is None:
|
|
19
20
|
XGATaskLangFuse.langfuse = setup_langfuse()
|
|
@@ -22,6 +23,7 @@ class XGATaskLangFuse:
|
|
|
22
23
|
self.task_id = task_id
|
|
23
24
|
self.task_run_id = task_run_id
|
|
24
25
|
self.task_no = task_no
|
|
26
|
+
self.user_id = user_id
|
|
25
27
|
self.agent_id = agent_id
|
|
26
28
|
|
|
27
29
|
self.trace_id = None
|
|
@@ -31,7 +33,7 @@ class XGATaskLangFuse:
|
|
|
31
33
|
|
|
32
34
|
def start_root_span(self,
|
|
33
35
|
root_span_name: str,
|
|
34
|
-
|
|
36
|
+
task_input: Dict[str, Any],
|
|
35
37
|
trace_id: Optional[str] = None):
|
|
36
38
|
if self.root_span is None:
|
|
37
39
|
trace = None
|
|
@@ -39,13 +41,23 @@ class XGATaskLangFuse:
|
|
|
39
41
|
self.trace_id = trace_id
|
|
40
42
|
trace = XGATaskLangFuse.langfuse.trace(id=trace_id)
|
|
41
43
|
else:
|
|
42
|
-
trace = XGATaskLangFuse.langfuse.trace(name="xga_task_engine")
|
|
44
|
+
trace = XGATaskLangFuse.langfuse.trace(name="xga_task_engine", session_id=self.session_id)
|
|
43
45
|
self.trace_id = trace.id
|
|
44
46
|
|
|
45
|
-
metadata = {
|
|
46
|
-
|
|
47
|
+
metadata = {
|
|
48
|
+
'task_id' : self.task_id,
|
|
49
|
+
'session_id' : self.session_id,
|
|
50
|
+
'user_id' : self.user_id,
|
|
51
|
+
'agent_id' : self.agent_id
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
self.root_span = trace.span(id=self.task_run_id,
|
|
55
|
+
name=f"{root_span_name}[{self.task_no}]",
|
|
56
|
+
input=task_input,
|
|
57
|
+
metadata=metadata)
|
|
47
58
|
self.root_span_name = root_span_name
|
|
48
59
|
|
|
60
|
+
logging.info(f"{root_span_name} TASK_INPUT: {task_input}")
|
|
49
61
|
|
|
50
62
|
def end_root_span(self, root_span_name:str, output: Optional[XGATaskResult]=None):
|
|
51
63
|
if self.root_span and self.root_span_name == root_span_name:
|
|
@@ -55,7 +67,7 @@ class XGATaskLangFuse:
|
|
|
55
67
|
|
|
56
68
|
|
|
57
69
|
def create_llm_langfuse_meta(self, llm_count:int)-> LangfuseMetadata:
|
|
58
|
-
generation_name = f"
|
|
70
|
+
generation_name = f"xga_engine_llm_completion[{self.task_no}]({llm_count})"
|
|
59
71
|
generation_id = f"{self.task_run_id}({llm_count})"
|
|
60
72
|
return LangfuseMetadata(
|
|
61
73
|
generation_name = generation_name,
|
|
@@ -14,7 +14,7 @@ langfuse = setup_langfuse()
|
|
|
14
14
|
def get_user_message(question)-> str:
|
|
15
15
|
while True:
|
|
16
16
|
user_message = input(f"\n💬 {question}: ")
|
|
17
|
-
if user_message.lower() == 'exit':
|
|
17
|
+
if user_message.lower() == 'exit' or user_message.lower() == 'quit':
|
|
18
18
|
print("\n====== Extreme General Agent Engine CLI EXIT ======")
|
|
19
19
|
sys.exit()
|
|
20
20
|
|
|
@@ -44,7 +44,7 @@ async def cli() -> None:
|
|
|
44
44
|
general_tools = ["*"]
|
|
45
45
|
|
|
46
46
|
while True:
|
|
47
|
-
user_message = get_user_message("Enter your message (or 'exit' to quit)")
|
|
47
|
+
user_message = get_user_message("Enter your task input message (or 'exit' to quit)")
|
|
48
48
|
|
|
49
49
|
print("\n🔄 Running XGA Engine ...\n")
|
|
50
50
|
engine = XGATaskEngine(tool_box=tool_box,
|
|
@@ -54,27 +54,24 @@ async def cli() -> None:
|
|
|
54
54
|
|
|
55
55
|
# Two task run in same langfuse trace
|
|
56
56
|
trace_id = langfuse.trace(name="xgae_cli").trace_id
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
trace_id=trace_id
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
if final_result["type"] == "ask":
|
|
64
|
-
await asyncio.sleep(1)
|
|
65
|
-
print(f"\n📌 ASK INFO: {final_result['content']}")
|
|
66
|
-
user_message = get_user_message("Enter ASK information (or 'exit' to quit)")
|
|
57
|
+
auto_continue = True
|
|
58
|
+
while auto_continue:
|
|
59
|
+
auto_continue = False
|
|
67
60
|
final_result = await engine.run_task_with_final_answer(
|
|
68
|
-
|
|
61
|
+
task_input={'role': "user", 'content': user_message},
|
|
69
62
|
trace_id=trace_id
|
|
70
63
|
)
|
|
71
64
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
65
|
+
if final_result["type"] == "ask":
|
|
66
|
+
await asyncio.sleep(1)
|
|
67
|
+
print(f"\n📌 ASK INFO: {final_result['content']}")
|
|
68
|
+
user_message = get_user_message("Enter ASK information (or 'exit' to quit)")
|
|
69
|
+
auto_continue = True
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
await asyncio.sleep(1)
|
|
73
|
+
result_prefix = "✅" if final_result["type"] == "answer" else "❌"
|
|
74
|
+
print(f"\n {result_prefix} FINAL RESULT: {final_result['content']}")
|
|
78
75
|
|
|
79
76
|
|
|
80
77
|
def main():
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xgae
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.19
|
|
4
4
|
Summary: Extreme General Agent Engine
|
|
5
5
|
Requires-Python: >=3.13
|
|
6
6
|
Requires-Dist: colorlog==6.9.0
|
|
7
7
|
Requires-Dist: langchain-mcp-adapters==0.1.9
|
|
8
|
+
Requires-Dist: langchain==0.3.27
|
|
8
9
|
Requires-Dist: langfuse==2.60.9
|
|
9
10
|
Requires-Dist: langgraph==0.6.5
|
|
10
11
|
Requires-Dist: litellm==1.74.15
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
xgae/__init__.py,sha256=
|
|
2
|
-
xgae/
|
|
1
|
+
xgae/__init__.py,sha256=oBX_YzTliM-343BAlR-sD7BUZmsCJ7PY2oYrGBhsdLM,79
|
|
2
|
+
xgae/engine_cli_app.py,sha256=FdmIpq8KDsgyZNfwCDgNX7FEZFeRFyGOt_H1oZF8aKs,2890
|
|
3
3
|
xgae/engine/engine_base.py,sha256=RR1em2wHiM2jP-peHt77SKdHWjnYOjdIIzN93zT61cA,1715
|
|
4
4
|
xgae/engine/mcp_tool_box.py,sha256=G4hKIMguwg1cO4Us2NMfdloYim8kuikVyVTIPucJr7o,10903
|
|
5
5
|
xgae/engine/prompt_builder.py,sha256=6I5rjgvNJ27QJ8DDuBTplutoPZdGs9LYFv3TSgT7zmc,5045
|
|
6
|
-
xgae/engine/task_engine.py,sha256=
|
|
7
|
-
xgae/engine/task_langfuse.py,sha256=
|
|
6
|
+
xgae/engine/task_engine.py,sha256=7B7nbERTh9HDgDH4lXS_s4KTsVU41AgR7rnN4jKLozQ,21588
|
|
7
|
+
xgae/engine/task_langfuse.py,sha256=J9suOhlIGSJor-mZsggPZf3XQld9dTkfpHAS2fVirvM,2859
|
|
8
8
|
xgae/engine/responser/non_stream_responser.py,sha256=zEJjqCgZVe2B8gkHYRFU7tmBV834f7w2a4Ws25P1N-c,5289
|
|
9
9
|
xgae/engine/responser/responser_base.py,sha256=jhl1Bdz1Fs3KofGEymThNXlQuCORFTTkTAR_U47krds,24403
|
|
10
10
|
xgae/engine/responser/stream_responser.py,sha256=cv4UGcxj8OksEogW7DUGTCvSJabu-DF6GceFyUwaXI4,7627
|
|
@@ -15,7 +15,7 @@ xgae/utils/llm_client.py,sha256=mWRtvtSMk_8NuzFReT9x52ayHlCNVZMZAltD6TQ-xZ8,1440
|
|
|
15
15
|
xgae/utils/misc.py,sha256=aMWOvJ9VW52q-L9Lkjl1hvXqLwpJAmyxA-Z8jzqFG0U,907
|
|
16
16
|
xgae/utils/setup_env.py,sha256=MqNG0c2QQBDFU1kI8frxr9kB5d08Mmi3QZ1OoorgIa0,2662
|
|
17
17
|
xgae/utils/xml_tool_parser.py,sha256=Mb0d8kBrfyAEvUwW1Nqir-3BgxZRr0ZX3WymQouuFSo,4859
|
|
18
|
-
xgae-0.1.
|
|
19
|
-
xgae-0.1.
|
|
20
|
-
xgae-0.1.
|
|
21
|
-
xgae-0.1.
|
|
18
|
+
xgae-0.1.19.dist-info/METADATA,sha256=MHUqZkPIWB9Tn_sLyFkFBw4XZKPAQqC_z0QudI1s5hk,343
|
|
19
|
+
xgae-0.1.19.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
20
|
+
xgae-0.1.19.dist-info/entry_points.txt,sha256=wmvgtMQbtzTbDPETS-tbQJD7jVlcs4hp0w6wOB0ooCc,229
|
|
21
|
+
xgae-0.1.19.dist-info/RECORD,,
|
|
File without changes
|