xgae 0.1.8__tar.gz → 0.1.10__tar.gz
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-0.1.8 → xgae-0.1.10}/.env +1 -0
- xgae-0.1.10/.idea/ai_toolkit.xml +6 -0
- {xgae-0.1.8 → xgae-0.1.10}/.idea/workspace.xml +20 -8
- {xgae-0.1.8 → xgae-0.1.10}/PKG-INFO +1 -1
- {xgae-0.1.8 → xgae-0.1.10}/pyproject.toml +3 -1
- xgae-0.1.10/src/examples/agent/langgraph/react/react_agent.py +177 -0
- {xgae-0.1.8/src/examples → xgae-0.1.10/src/examples/engine}/run_human_in_loop.py +18 -3
- {xgae-0.1.8/src/examples → xgae-0.1.10/src/examples/engine}/run_simple.py +10 -2
- {xgae-0.1.8/src/examples → xgae-0.1.10/src/examples/engine}/run_user_prompt.py +6 -1
- xgae-0.1.10/src/examples/tools/custom_fault_tools_app.py +104 -0
- xgae-0.1.10/src/xgae/__init__.py +4 -0
- xgae-0.1.10/src/xgae/cli_app.py +87 -0
- {xgae-0.1.8 → xgae-0.1.10}/src/xgae/engine/engine_base.py +1 -1
- {xgae-0.1.8 → xgae-0.1.10}/src/xgae/engine/mcp_tool_box.py +6 -1
- {xgae-0.1.8 → xgae-0.1.10}/src/xgae/engine/prompt_builder.py +1 -1
- {xgae-0.1.8 → xgae-0.1.10}/src/xgae/engine/responser/non_stream_responser.py +7 -3
- {xgae-0.1.8 → xgae-0.1.10}/src/xgae/engine/responser/responser_base.py +9 -9
- {xgae-0.1.8 → xgae-0.1.10}/src/xgae/engine/task_engine.py +72 -84
- xgae-0.1.10/src/xgae/engine/task_langfuse.py +65 -0
- {xgae-0.1.8 → xgae-0.1.10}/src/xgae/tools/without_general_tools_app.py +1 -1
- {xgae-0.1.8 → xgae-0.1.10}/src/xgae/utils/__init__.py +6 -0
- {xgae-0.1.8 → xgae-0.1.10}/src/xgae/utils/json_helpers.py +7 -13
- {xgae-0.1.8 → xgae-0.1.10}/src/xgae/utils/llm_client.py +36 -17
- {xgae-0.1.8 → xgae-0.1.10}/src/xgae/utils/misc.py +3 -1
- {xgae-0.1.8 → xgae-0.1.10}/src/xgae/utils/setup_env.py +32 -29
- {xgae-0.1.8 → xgae-0.1.10}/src/xgae/utils/xml_tool_parser.py +4 -80
- xgae-0.1.8/templates/example_user_prompt.txt → xgae-0.1.10/templates/example/fault_user_prompt.txt +2 -2
- {xgae-0.1.8 → xgae-0.1.10}/test/test_langfuse.py +4 -1
- {xgae-0.1.8 → xgae-0.1.10}/uv.lock +1 -1
- xgae-0.1.8/src/xgae/__init__.py +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/.idea/.gitignore +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/.idea/inspectionProfiles/Project_Default.xml +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/.idea/misc.xml +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/.idea/modules.xml +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/.idea/vcs.xml +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/.idea/xgae.iml +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/.python-version +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/README.md +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/mcpservers/custom_servers.json +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/mcpservers/xga_server.json +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/mcpservers/xga_server_sse.json +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/src/xgae/engine/responser/stream_responser.py +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/templates/custom_tool_prompt_template.txt +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/templates/gemini_system_prompt_template.txt +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/templates/general_tool_prompt_template.txt +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/templates/system_prompt_response_sample.txt +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/templates/system_prompt_template.txt +0 -0
- {xgae-0.1.8 → xgae-0.1.10}/test/test_litellm_langfuse.py +0 -0
{xgae-0.1.8 → xgae-0.1.10}/.env
RENAMED
|
@@ -28,23 +28,27 @@
|
|
|
28
28
|
<component name="PropertiesComponent"><![CDATA[{
|
|
29
29
|
"keyToString": {
|
|
30
30
|
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
|
31
|
+
"Python.__init__.executor": "Run",
|
|
31
32
|
"Python.llm_client.executor": "Run",
|
|
32
33
|
"Python.mcp_tool_box.executor": "Run",
|
|
33
34
|
"Python.message_tools_app.executor": "Run",
|
|
34
35
|
"Python.responser_base.executor": "Run",
|
|
35
36
|
"Python.run_engine_with_human_in_loop.executor": "Run",
|
|
37
|
+
"Python.run_human_in_loop.executor": "Run",
|
|
36
38
|
"Python.run_simple.executor": "Run",
|
|
37
39
|
"Python.run_task_engine.executor": "Run",
|
|
38
40
|
"Python.run_user_prompt.executor": "Run",
|
|
39
41
|
"Python.run_xga_engine.executor": "Run",
|
|
40
42
|
"Python.setup_env.executor": "Run",
|
|
41
43
|
"Python.task_engine.executor": "Run",
|
|
44
|
+
"Python.task_langfuse.executor": "Debug",
|
|
42
45
|
"Python.test_langfuse.executor": "Run",
|
|
43
46
|
"Python.test_litellm_langfuse.executor": "Run",
|
|
44
47
|
"Python.utils.executor": "Run",
|
|
45
48
|
"Python.xga_engine.executor": "Run",
|
|
46
49
|
"Python.xga_mcp_tool_box.executor": "Debug",
|
|
47
50
|
"Python.xga_prompt_builder.executor": "Debug",
|
|
51
|
+
"Python.xgae_cli.executor": "Run",
|
|
48
52
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
49
53
|
"last_opened_file_path": "/Users/sharkystar/DevProjects/xga/xgae",
|
|
50
54
|
"node.js.detected.package.eslint": "true",
|
|
@@ -58,6 +62,8 @@
|
|
|
58
62
|
}]]></component>
|
|
59
63
|
<component name="RecentsManager">
|
|
60
64
|
<key name="MoveFile.RECENT_KEYS">
|
|
65
|
+
<recent name="$PROJECT_DIR$/src/examples" />
|
|
66
|
+
<recent name="$PROJECT_DIR$/src/examples/engine" />
|
|
61
67
|
<recent name="$PROJECT_DIR$/src/xgae/engine/responser" />
|
|
62
68
|
</key>
|
|
63
69
|
</component>
|
|
@@ -164,7 +170,9 @@
|
|
|
164
170
|
<workItem from="1755737435202" duration="48139000" />
|
|
165
171
|
<workItem from="1756044658912" duration="1248000" />
|
|
166
172
|
<workItem from="1756082326044" duration="23657000" />
|
|
167
|
-
<workItem from="1756168626188" duration="
|
|
173
|
+
<workItem from="1756168626188" duration="52435000" />
|
|
174
|
+
<workItem from="1756305726553" duration="2819000" />
|
|
175
|
+
<workItem from="1756340066915" duration="14276000" />
|
|
168
176
|
</task>
|
|
169
177
|
<servers />
|
|
170
178
|
</component>
|
|
@@ -184,21 +192,25 @@
|
|
|
184
192
|
</component>
|
|
185
193
|
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
|
186
194
|
<SUITE FILE_PATH="coverage/xgae$test_litellm_langfuse.coverage" NAME="test_litellm_langfuse Coverage Results" MODIFIED="1756196476262" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
195
|
+
<SUITE FILE_PATH="coverage/xgae$task_langfuse.coverage" NAME="task_langfuse Coverage Results" MODIFIED="1756306181167" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
187
196
|
<SUITE FILE_PATH="coverage/xgae$xga_engine.coverage" NAME="xga_engine Coverage Results" MODIFIED="1755580277172" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
188
|
-
<SUITE FILE_PATH="coverage/xgae$run_simple.coverage" NAME="run_simple Coverage Results" MODIFIED="
|
|
197
|
+
<SUITE FILE_PATH="coverage/xgae$run_simple.coverage" NAME="run_simple Coverage Results" MODIFIED="1756359842556" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
198
|
+
<SUITE FILE_PATH="coverage/xgae$run_human_in_loop.coverage" NAME="run_human_in_loop Coverage Results" MODIFIED="1756279131815" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
189
199
|
<SUITE FILE_PATH="coverage/xgae$run_xga_engine.coverage" NAME="run_task_engine Coverage Results" MODIFIED="1756111613459" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
190
200
|
<SUITE FILE_PATH="coverage/xgae$message_tools_app.coverage" NAME="message_tools_app Coverage Results" MODIFIED="1756094157566" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
191
201
|
<SUITE FILE_PATH="coverage/xgae$run_engine_with_human_in_loop.coverage" NAME="run_engine_with_human_in_loop Coverage Results" MODIFIED="1756089269027" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
202
|
+
<SUITE FILE_PATH="coverage/xgae$__init__.coverage" NAME="__init__ Coverage Results" MODIFIED="1756345820610" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
192
203
|
<SUITE FILE_PATH="coverage/xgae$xga_prompt_builder.coverage" NAME="xga_prompt_builder Coverage Results" MODIFIED="1755587456555" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
193
204
|
<SUITE FILE_PATH="coverage/xgae$test_langfuse.coverage" NAME="test_langfuse Coverage Results" MODIFIED="1756196410142" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
194
|
-
<SUITE FILE_PATH="coverage/xgae$run_task_engine.coverage" NAME="run_task_engine Coverage Results" MODIFIED="
|
|
205
|
+
<SUITE FILE_PATH="coverage/xgae$run_task_engine.coverage" NAME="run_task_engine Coverage Results" MODIFIED="1756341371676" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
195
206
|
<SUITE FILE_PATH="coverage/xgae$responser_base.coverage" NAME="responser_base Coverage Results" MODIFIED="1756103040764" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
196
|
-
<SUITE FILE_PATH="coverage/xgae$mcp_tool_box.coverage" NAME="mcp_tool_box Coverage Results" MODIFIED="
|
|
207
|
+
<SUITE FILE_PATH="coverage/xgae$mcp_tool_box.coverage" NAME="mcp_tool_box Coverage Results" MODIFIED="1756274403389" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
197
208
|
<SUITE FILE_PATH="coverage/xgae$utils.coverage" NAME="utils Coverage Results" MODIFIED="1755226923439" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
198
|
-
<SUITE FILE_PATH="coverage/xgae$setup_env.coverage" NAME="setup_env Coverage Results" MODIFIED="
|
|
199
|
-
<SUITE FILE_PATH="coverage/xgae$run_user_prompt.coverage" NAME="run_user_prompt Coverage Results" MODIFIED="
|
|
209
|
+
<SUITE FILE_PATH="coverage/xgae$setup_env.coverage" NAME="setup_env Coverage Results" MODIFIED="1756273791782" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
210
|
+
<SUITE FILE_PATH="coverage/xgae$run_user_prompt.coverage" NAME="run_user_prompt Coverage Results" MODIFIED="1756279512361" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
211
|
+
<SUITE FILE_PATH="coverage/xgae$xgae_cli.coverage" NAME="xgae_cli Coverage Results" MODIFIED="1756347000850" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
200
212
|
<SUITE FILE_PATH="coverage/xgae$xga_mcp_tool_box.coverage" NAME="xga_mcp_tool_box Coverage Results" MODIFIED="1755583099719" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
201
|
-
<SUITE FILE_PATH="coverage/xgae$
|
|
202
|
-
<SUITE FILE_PATH="coverage/xgae$
|
|
213
|
+
<SUITE FILE_PATH="coverage/xgae$task_engine.coverage" NAME="task_engine Coverage Results" MODIFIED="1756308226461" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
214
|
+
<SUITE FILE_PATH="coverage/xgae$llm_client.coverage" NAME="llm_client Coverage Results" MODIFIED="1756308364265" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
203
215
|
</component>
|
|
204
216
|
</project>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "xgae"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.10"
|
|
4
4
|
description = "Extreme General Agent Engine"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.13"
|
|
@@ -21,4 +21,6 @@ build-backend = "hatchling.build"
|
|
|
21
21
|
exclude = ["log/*"]
|
|
22
22
|
|
|
23
23
|
[project.scripts]
|
|
24
|
+
xgae = "xgae.cli_app:main"
|
|
24
25
|
xgae-tools = "xgae.tools.without_general_tools_app:main"
|
|
26
|
+
custom_fault_tools = "examples.tools.custom_fault_tools_app:main"
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Any, Dict, List, Annotated, Sequence, TypedDict
|
|
4
|
+
|
|
5
|
+
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage
|
|
6
|
+
from langgraph.checkpoint.memory import MemorySaver
|
|
7
|
+
from langgraph.graph import END, START, StateGraph
|
|
8
|
+
from langgraph.graph.message import add_messages
|
|
9
|
+
|
|
10
|
+
from xgae.engine.engine_base import XGATaskResult, XGAResponseMessage
|
|
11
|
+
from xgae.engine.mcp_tool_box import XGAMcpToolBox
|
|
12
|
+
from xgae.utils.setup_env import setup_langfuse, setup_logging
|
|
13
|
+
from xgae.utils import handle_error
|
|
14
|
+
from xgae.utils.misc import read_file
|
|
15
|
+
|
|
16
|
+
class TaskState(TypedDict, total=False):
|
|
17
|
+
"""State definition for the agent orchestration graph"""
|
|
18
|
+
messages: Annotated[Sequence[BaseMessage], add_messages]
|
|
19
|
+
user_input: str
|
|
20
|
+
next_node: str
|
|
21
|
+
context: Dict[str, Any]
|
|
22
|
+
system_prompt: str
|
|
23
|
+
custom_tools: List[str]
|
|
24
|
+
general_tools: List[str]
|
|
25
|
+
task_result: XGATaskResult
|
|
26
|
+
formatted_result: XGATaskResult
|
|
27
|
+
iteration_count: int
|
|
28
|
+
|
|
29
|
+
langfuse = setup_langfuse()
|
|
30
|
+
|
|
31
|
+
class XGAReactAgent:
|
|
32
|
+
MAX_TASK_RETRY = 2
|
|
33
|
+
def __init__(self):
|
|
34
|
+
self.tool_box = XGAMcpToolBox()
|
|
35
|
+
|
|
36
|
+
async def _create_graph(self) -> StateGraph:
|
|
37
|
+
try:
|
|
38
|
+
graph_builder = StateGraph(TaskState)
|
|
39
|
+
|
|
40
|
+
# Add nodes
|
|
41
|
+
graph_builder.add_node("supervisor", self._supervisor_node)
|
|
42
|
+
graph_builder.add_node("select_tool", self._select_tool_node)
|
|
43
|
+
graph_builder.add_node("exec_task", self._exec_task_node)
|
|
44
|
+
graph_builder.add_node("eval_result", self._eval_result_node)
|
|
45
|
+
graph_builder.add_node("format_result", self._format_result_node)
|
|
46
|
+
|
|
47
|
+
# Add edges
|
|
48
|
+
graph_builder.add_edge(START, "supervisor")
|
|
49
|
+
graph_builder.add_conditional_edges(
|
|
50
|
+
"supervisor",
|
|
51
|
+
self._next_condition,
|
|
52
|
+
{
|
|
53
|
+
"select_tool": "select_tool",
|
|
54
|
+
"exec_task": "exec_task",
|
|
55
|
+
"format_result": "format_result"
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
graph_builder.add_edge("select_tool", "exec_task")
|
|
60
|
+
graph_builder.add_edge("exec_task", "eval_result")
|
|
61
|
+
|
|
62
|
+
graph_builder.add_conditional_edges(
|
|
63
|
+
"eval_result",
|
|
64
|
+
self._next_condition,
|
|
65
|
+
{
|
|
66
|
+
"retry": "supervisor",
|
|
67
|
+
"format_result": "format_result",
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
graph_builder.add_edge("format_result", END)
|
|
72
|
+
|
|
73
|
+
graph = graph_builder.compile(checkpointer=MemorySaver())
|
|
74
|
+
graph.name = "XGARectAgent"
|
|
75
|
+
|
|
76
|
+
return graph
|
|
77
|
+
except Exception as e:
|
|
78
|
+
logging.error("Failed to create XGARectAgent graph: %s", str(e))
|
|
79
|
+
raise
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
async def _supervisor_node(self, state: TaskState) -> Dict[str, Any]:
|
|
83
|
+
user_input = state.get("user_input", "")
|
|
84
|
+
system_prompt = None if "fault" in user_input else read_file("templates/example/fault_user_prompt.txt")
|
|
85
|
+
return {
|
|
86
|
+
"system_prompt" : system_prompt,
|
|
87
|
+
"next_node" : "select_tool",
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async def _select_tool_node(self, state: TaskState) -> Dict[str, Any]:
|
|
91
|
+
system_prompt = state.get("system_prompt",None)
|
|
92
|
+
general_tools = ["*"] if system_prompt else []
|
|
93
|
+
custom_tools = ["*"] if not system_prompt else []
|
|
94
|
+
return {
|
|
95
|
+
"general_tools" : general_tools,
|
|
96
|
+
"custom_tools" : custom_tools,
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async def _exec_task_node(self, state: TaskState) -> Dict[str, Any]:
|
|
100
|
+
task_result = XGATaskResult(type="answer", content="test task result")
|
|
101
|
+
return {
|
|
102
|
+
"task_result" : task_result
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async def _eval_result_node(self, state: TaskState) -> Dict[str, Any]:
|
|
106
|
+
next_node = "end"
|
|
107
|
+
return {
|
|
108
|
+
"next_node" : next_node
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async def _format_result_node(self, state: TaskState) -> Dict[str, Any]:
|
|
112
|
+
formatted_result = state.get("task_result")
|
|
113
|
+
return {
|
|
114
|
+
"formatted_result" : formatted_result,
|
|
115
|
+
"messages": state["messages"] + [AIMessage(content=f"")]
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
def _next_condition(self, state: TaskState) -> str:
|
|
119
|
+
next_node = state.get("next_node")
|
|
120
|
+
return next_node
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
async def generate(self, user_input: str) -> XGATaskResult:
|
|
124
|
+
result = None
|
|
125
|
+
try:
|
|
126
|
+
logging.info("****** Start React Agent for user_input: %s", user_input)
|
|
127
|
+
|
|
128
|
+
# Create graph if not already created
|
|
129
|
+
if self.graph is None:
|
|
130
|
+
self.graph = await self._create_graph()
|
|
131
|
+
|
|
132
|
+
# Initialize state
|
|
133
|
+
initial_state = {
|
|
134
|
+
"messages": [HumanMessage(content=f"information for: {user_input}")],
|
|
135
|
+
"user_input": user_input,
|
|
136
|
+
"next_node": None,
|
|
137
|
+
"tasks": [],
|
|
138
|
+
"context": "",
|
|
139
|
+
"current_task": None,
|
|
140
|
+
"next_task": None,
|
|
141
|
+
"formatted_result": "",
|
|
142
|
+
"final_error_info": "",
|
|
143
|
+
"iteration_count": 1
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
# Run the retrieval graph with proper configuration
|
|
147
|
+
config = {"recursion_limit": 100,
|
|
148
|
+
"configurable": {"thread_id": "manager_async_generate_thread"}}
|
|
149
|
+
final_state = await self.graph.ainvoke(initial_state, config=config)
|
|
150
|
+
|
|
151
|
+
# Parse and return formatted results
|
|
152
|
+
result = final_state["formatted_result"]
|
|
153
|
+
|
|
154
|
+
logging.info("=" * 100)
|
|
155
|
+
logging.info("User question: %s", user_input)
|
|
156
|
+
logging.info("User answer: %s", result)
|
|
157
|
+
logging.info("=" * 100)
|
|
158
|
+
|
|
159
|
+
return result
|
|
160
|
+
except Exception as e:
|
|
161
|
+
logging.error("### Error ManagerAgent _agent_work for user_input '%s': %s ###", user_input, str(e))
|
|
162
|
+
handle_error(e)
|
|
163
|
+
result = XGATaskResult(type="error", content="Never get result, Unexpected Error")
|
|
164
|
+
return result
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
if __name__ == "__main__":
|
|
168
|
+
setup_logging()
|
|
169
|
+
|
|
170
|
+
agent = XGAReactAgent()
|
|
171
|
+
user_inputs = [
|
|
172
|
+
"Create a function to sort a list of numbers, sort [6,8,7,5]"
|
|
173
|
+
, "sort [3,2,7,5]"
|
|
174
|
+
]
|
|
175
|
+
for user_input in user_inputs:
|
|
176
|
+
result = agent.generate(user_input)
|
|
177
|
+
print(result)
|
|
@@ -5,10 +5,16 @@ from xgae.engine.task_engine import XGATaskEngine
|
|
|
5
5
|
from xgae.utils.llm_client import LLMConfig
|
|
6
6
|
from xgae.utils.misc import read_file
|
|
7
7
|
|
|
8
|
+
from xgae.utils.setup_env import setup_langfuse, setup_logging
|
|
9
|
+
|
|
10
|
+
setup_logging()
|
|
11
|
+
langfuse = setup_langfuse()
|
|
8
12
|
|
|
9
13
|
async def main() -> None:
|
|
14
|
+
# Before Run Exec: uv run custom_fault_tools
|
|
10
15
|
tool_box = XGAMcpToolBox(custom_mcp_server_file="mcpservers/custom_servers.json")
|
|
11
|
-
system_prompt = read_file("templates/
|
|
16
|
+
system_prompt = read_file("templates/example/fault_user_prompt.txt")
|
|
17
|
+
|
|
12
18
|
engine = XGATaskEngine(tool_box=tool_box,
|
|
13
19
|
general_tools=[],
|
|
14
20
|
custom_tools=["*"],
|
|
@@ -16,14 +22,23 @@ async def main() -> None:
|
|
|
16
22
|
system_prompt=system_prompt,
|
|
17
23
|
max_auto_run=8)
|
|
18
24
|
|
|
25
|
+
# Two task run in same langfuse trace
|
|
26
|
+
trace_id = langfuse.trace(name="xgae_example_run_human_in_loop").trace_id
|
|
27
|
+
|
|
19
28
|
user_input = "locate fault and solution"
|
|
20
|
-
final_result = await engine.run_task_with_final_answer(
|
|
29
|
+
final_result = await engine.run_task_with_final_answer(
|
|
30
|
+
task_message={"role": "user", "content": user_input},
|
|
31
|
+
trace_id=trace_id
|
|
32
|
+
)
|
|
21
33
|
print("FINAL RESULT:", final_result)
|
|
22
34
|
|
|
23
35
|
if final_result["type"] == "ask":
|
|
24
36
|
print("====== Wait for user input ... ======")
|
|
25
37
|
user_input = "ip=10.0.1.1"
|
|
26
|
-
final_result = await engine.run_task_with_final_answer(
|
|
38
|
+
final_result = await engine.run_task_with_final_answer(
|
|
39
|
+
task_message={"role": "user", "content": user_input},
|
|
40
|
+
trace_id=trace_id
|
|
41
|
+
)
|
|
27
42
|
print("FINAL RESULT:", final_result)
|
|
28
43
|
|
|
29
44
|
asyncio.run(main())
|
|
@@ -3,10 +3,18 @@ import asyncio
|
|
|
3
3
|
from xgae.engine.task_engine import XGATaskEngine
|
|
4
4
|
from xgae.utils.llm_client import LLMConfig
|
|
5
5
|
|
|
6
|
+
from xgae.utils.setup_env import setup_logging
|
|
7
|
+
|
|
8
|
+
setup_logging()
|
|
6
9
|
|
|
7
10
|
async def main() -> None:
|
|
8
|
-
engine = XGATaskEngine(llm_config=LLMConfig(stream=False), max_auto_run=
|
|
9
|
-
|
|
11
|
+
engine = XGATaskEngine(llm_config=LLMConfig(stream=False), max_auto_run=3)
|
|
12
|
+
|
|
13
|
+
final_result = await engine.run_task_with_final_answer(
|
|
14
|
+
task_message={"role": "user", "content": "1+7"}
|
|
15
|
+
)
|
|
16
|
+
|
|
10
17
|
print("FINAL RESULT:", final_result)
|
|
11
18
|
|
|
19
|
+
|
|
12
20
|
asyncio.run(main())
|
|
@@ -5,10 +5,15 @@ from xgae.engine.task_engine import XGATaskEngine
|
|
|
5
5
|
from xgae.utils.llm_client import LLMConfig
|
|
6
6
|
from xgae.utils.misc import read_file
|
|
7
7
|
|
|
8
|
+
from xgae.utils.setup_env import setup_logging
|
|
9
|
+
|
|
10
|
+
setup_logging()
|
|
8
11
|
|
|
9
12
|
async def main() -> None:
|
|
13
|
+
# Before Run Exec: uv run custom_fault_tools
|
|
10
14
|
tool_box = XGAMcpToolBox(custom_mcp_server_file="mcpservers/custom_servers.json")
|
|
11
|
-
system_prompt = read_file("templates/
|
|
15
|
+
system_prompt = read_file("templates/example/fault_user_prompt.txt")
|
|
16
|
+
|
|
12
17
|
engine = XGATaskEngine(tool_box=tool_box,
|
|
13
18
|
general_tools=[],
|
|
14
19
|
custom_tools=["*"],
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
from typing import Dict, Any
|
|
6
|
+
from pydantic import Field
|
|
7
|
+
|
|
8
|
+
from mcp.server.fastmcp import FastMCP
|
|
9
|
+
|
|
10
|
+
mcp = FastMCP(name="Fault Location Tools")
|
|
11
|
+
alarm_type = 0
|
|
12
|
+
|
|
13
|
+
@mcp.tool(
|
|
14
|
+
description="Get Alarm Object",
|
|
15
|
+
)
|
|
16
|
+
def get_alarm(ip: Annotated[str, Field(description="Alarm Object IP Address")]) -> Dict[str, str]:
|
|
17
|
+
logging.info(f"get_alarm: ip={ip}")
|
|
18
|
+
return {"alarmId":"alm0123", "objId": "obj567"}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@mcp.tool(
|
|
22
|
+
description="Get alarm type, return result enum: 1: Business Type Alarm; 2: Equipment Type Alarm; 3: Middleware Type Alarm",
|
|
23
|
+
)
|
|
24
|
+
def get_alarm_type(alarm_id: Annotated[str, Field(description="Alarm Object Id")]) -> str:
|
|
25
|
+
logging.info(f"get_alarm_type: alarm_id={alarm_id}, alarm_type={alarm_type}")
|
|
26
|
+
return f"{alarm_type}"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@mcp.tool(
|
|
30
|
+
description="Locate Business Type Fault",
|
|
31
|
+
)
|
|
32
|
+
def get_busi_fault(obj_id: Annotated[str, Field(description="Alarm Object Id")]) -> Dict[str, Any]:
|
|
33
|
+
logging.info(f"get_busi_fault: obj_id={obj_id}")
|
|
34
|
+
return {"fault_code": "F01", "fault_desc": "Business Recharge Fault"}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@mcp.tool(
|
|
38
|
+
description="Locate Equipment Type Fault",
|
|
39
|
+
)
|
|
40
|
+
def get_equip_fault(obj_id: Annotated[str, Field(description="Alarm Object Id")]) -> Dict[str, Any]:
|
|
41
|
+
logging.info(f"get_equip_fault: obj_id={obj_id}")
|
|
42
|
+
return {"fault_code": "F02", "fault_desc": "Host Disk Fault"}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@mcp.tool(
|
|
46
|
+
description="Locate Middleware Type Fault",
|
|
47
|
+
)
|
|
48
|
+
def get_middle_fault(obj_id: Annotated[str, Field(description="Alarm Object Id")]) -> Dict[str, Any]:
|
|
49
|
+
logging.info(f"get_middle_fault: obj_id={obj_id}")
|
|
50
|
+
return {"fault_code": "F03", "fault_desc": "Redis Fault"}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@mcp.tool(
|
|
54
|
+
description="Get Business Type Fault Solution and Cause",
|
|
55
|
+
)
|
|
56
|
+
async def get_busi_fault_cause(fault_code: Annotated[str, Field(description="Fault Code")]) -> str:
|
|
57
|
+
logging.info(f"get_busi_fault_cause: faultCode={fault_code}")
|
|
58
|
+
|
|
59
|
+
fault_cause = ""
|
|
60
|
+
if (fault_code == 'F01'):
|
|
61
|
+
fault_cause = "Business Recharge Fault, Fault Cause is 'Phone Recharge Application Crash' ,Solution is 'Restart Phone Recharge Application'"
|
|
62
|
+
else:
|
|
63
|
+
fault_cause = f"FaultCode '{fault_code}' is not Business Type"
|
|
64
|
+
|
|
65
|
+
return fault_cause
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@mcp.tool(
|
|
69
|
+
description="Get Equipment Type Fault Solution and Cause",
|
|
70
|
+
)
|
|
71
|
+
async def get_equip_fault_cause(fault_code: Annotated[str, Field(description="Fault Code")]) -> str:
|
|
72
|
+
logging.info(f"get_equip_fault_cause: faultCode={fault_code}")
|
|
73
|
+
|
|
74
|
+
fault_cause = ""
|
|
75
|
+
if (fault_code == 'F01'):
|
|
76
|
+
fault_cause = "Host Fault, Fault Cause is 'Host Disk is Damaged' ,Solution is 'Change Host Disk'"
|
|
77
|
+
else:
|
|
78
|
+
fault_cause = f"FaultCode '{fault_code}' is not Equipment Type"
|
|
79
|
+
|
|
80
|
+
return fault_cause
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@click.command()
|
|
84
|
+
@click.option("--transport", type=click.Choice(["stdio", "sse"]), default="sse", help="Transport type")
|
|
85
|
+
@click.option("--host", default="0.0.0.0", help="Host to listen on for SSE")
|
|
86
|
+
@click.option("--port", default=17070, help="Port to listen on for SSE")
|
|
87
|
+
@click.option("--alarmtype", default=1, help="AlarmType Set")
|
|
88
|
+
def main(transport: str, host: str, port: int, alarmtype:int):
|
|
89
|
+
if transport != "stdio":
|
|
90
|
+
from xgae.utils.setup_env import setup_logging
|
|
91
|
+
setup_logging()
|
|
92
|
+
logging.info("=" * 20 + f" Custom Fault Tools Sever Started in {transport} mode " + "=" * 20)
|
|
93
|
+
|
|
94
|
+
global alarm_type
|
|
95
|
+
alarm_type = alarmtype
|
|
96
|
+
|
|
97
|
+
mcp.settings.host = host
|
|
98
|
+
mcp.settings.port = port
|
|
99
|
+
|
|
100
|
+
mcp.run(transport=transport)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == '__main__':
|
|
104
|
+
main()
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from xgae.engine.mcp_tool_box import XGAMcpToolBox
|
|
5
|
+
from xgae.engine.task_engine import XGATaskEngine
|
|
6
|
+
from xgae.utils.llm_client import LLMConfig
|
|
7
|
+
from xgae.utils.misc import read_file
|
|
8
|
+
|
|
9
|
+
from xgae.utils.setup_env import setup_langfuse, setup_env_logging
|
|
10
|
+
|
|
11
|
+
setup_env_logging()
|
|
12
|
+
langfuse = setup_langfuse()
|
|
13
|
+
|
|
14
|
+
def get_user_message(question)-> str:
|
|
15
|
+
while True:
|
|
16
|
+
user_message = input(f"\n💬 {question}: ")
|
|
17
|
+
if user_message.lower() == 'exit':
|
|
18
|
+
print("\n====== Extreme General Agent Engine CLI EXIT ======")
|
|
19
|
+
sys.exit()
|
|
20
|
+
|
|
21
|
+
if not user_message.strip():
|
|
22
|
+
print("\nuser message is empty, input agin !!!\n")
|
|
23
|
+
continue
|
|
24
|
+
|
|
25
|
+
return user_message
|
|
26
|
+
|
|
27
|
+
async def cli() -> None:
|
|
28
|
+
await asyncio.sleep(1)
|
|
29
|
+
print("\n====== Extreme General Agent Engine CLI START ======")
|
|
30
|
+
user_message = input("\n💬 Start Custom MCP Server and Load User Prompt (Yes/No): ")
|
|
31
|
+
tool_box = None
|
|
32
|
+
system_prompt = None
|
|
33
|
+
general_tools = []
|
|
34
|
+
custom_tools = []
|
|
35
|
+
if user_message.lower() == 'yes':
|
|
36
|
+
print(f"--- Start Custom MCP Server in custom_servers.json")
|
|
37
|
+
print(f"--- Load User Prompt in example/fault_user_prompt.txt")
|
|
38
|
+
tool_box = XGAMcpToolBox(custom_mcp_server_file="mcpservers/custom_servers.json")
|
|
39
|
+
system_prompt = read_file("templates/example/fault_user_prompt.txt")
|
|
40
|
+
custom_tools = ["*"]
|
|
41
|
+
else:
|
|
42
|
+
print(f"--- Start General Agent Server")
|
|
43
|
+
print(f"--- Load System Prompt")
|
|
44
|
+
general_tools = ["*"]
|
|
45
|
+
|
|
46
|
+
while True:
|
|
47
|
+
user_message = get_user_message("Enter your message (or 'exit' to quit)")
|
|
48
|
+
|
|
49
|
+
print("\n🔄 Running XGA Engine ...\n")
|
|
50
|
+
engine = XGATaskEngine(tool_box=tool_box,
|
|
51
|
+
general_tools=general_tools,
|
|
52
|
+
custom_tools=custom_tools,
|
|
53
|
+
llm_config=LLMConfig(stream=False),
|
|
54
|
+
system_prompt=system_prompt,
|
|
55
|
+
max_auto_run=8)
|
|
56
|
+
|
|
57
|
+
# Two task run in same langfuse trace
|
|
58
|
+
trace_id = langfuse.trace(name="xgae_cli").trace_id
|
|
59
|
+
|
|
60
|
+
final_result = await engine.run_task_with_final_answer(
|
|
61
|
+
task_message={"role": "user", "content": user_message},
|
|
62
|
+
trace_id=trace_id
|
|
63
|
+
)
|
|
64
|
+
|
|
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
|
+
final_result = await engine.run_task_with_final_answer(
|
|
70
|
+
task_message={"role": "user", "content": user_message},
|
|
71
|
+
trace_id=trace_id
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
await asyncio.sleep(1)
|
|
75
|
+
result_prefix = "✅" if final_result["type"] == "answer" else "❌"
|
|
76
|
+
if final_result["type"] == "ask":
|
|
77
|
+
print("\n *** IMPORTANT: XGA CLI only support showing ONE TURN ASK !")
|
|
78
|
+
result_prefix = "⚠️"
|
|
79
|
+
print(f"\n {result_prefix} FINAL RESULT: {final_result['content']}")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def main():
|
|
83
|
+
asyncio.run(cli())
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
if __name__ == "__main__":
|
|
87
|
+
main()
|
|
@@ -7,7 +7,7 @@ class XGAError(Exception):
|
|
|
7
7
|
pass
|
|
8
8
|
|
|
9
9
|
XGAMsgStatusType = Literal["error", "finish", "tool_error", "tool_started", "tool_completed", "tool_failed", "thread_run_start", "thread_run_end", "assistant_response_start", "assistant_response_end"]
|
|
10
|
-
XGAResponseMsgType = Literal["user", "status", "tool", "assistant"]
|
|
10
|
+
XGAResponseMsgType = Literal["user", "status", "tool", "assistant", "assistant_complete"]
|
|
11
11
|
|
|
12
12
|
class XGAResponseMessage(TypedDict, total=False):
|
|
13
13
|
message_id: str
|
|
@@ -190,11 +190,16 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
190
190
|
if __name__ == "__main__":
|
|
191
191
|
import asyncio
|
|
192
192
|
from dataclasses import asdict
|
|
193
|
+
from xgae.utils.setup_env import setup_logging
|
|
194
|
+
|
|
195
|
+
setup_logging()
|
|
193
196
|
|
|
194
197
|
async def main():
|
|
195
|
-
|
|
198
|
+
## Before Run Exec: uv run custom_fault_tools
|
|
196
199
|
mcp_tool_box = XGAMcpToolBox(custom_mcp_server_file="mcpservers/custom_servers.json")
|
|
197
200
|
#mcp_tool_box = XGAMcpToolBox()
|
|
201
|
+
|
|
202
|
+
task_id = "task1"
|
|
198
203
|
await mcp_tool_box.load_mcp_tools_schema()
|
|
199
204
|
await mcp_tool_box.creat_task_tool_box(task_id=task_id, general_tools=["*"], custom_tools=["bomc_fault.*"])
|
|
200
205
|
tool_schemas = mcp_tool_box.get_task_tool_schemas(task_id, "general_tool")
|