xgae 0.1.1__tar.gz → 0.1.2__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.1 → xgae-0.1.2}/.idea/misc.xml +1 -1
- {xgae-0.1.1 → xgae-0.1.2}/.idea/workspace.xml +65 -15
- {xgae-0.1.1 → xgae-0.1.2}/.idea/xgae.iml +1 -1
- {xgae-0.1.1 → xgae-0.1.2}/PKG-INFO +1 -1
- {xgae-0.1.1 → xgae-0.1.2}/pyproject.toml +1 -1
- {xgae-0.1.1 → xgae-0.1.2}/src/xgae/engine/xga_base.py +2 -1
- xgae-0.1.2/src/xgae/engine/xga_engine.py +105 -0
- {xgae-0.1.1 → xgae-0.1.2}/src/xgae/engine/xga_mcp_tool_box.py +39 -18
- xgae-0.1.2/src/xgae/engine/xga_prompt_builder.py +115 -0
- {xgae-0.1.1 → xgae-0.1.2}/src/xgae/utils/llm_client.py +2 -5
- xgae-0.1.2/src/xgae/utils/setup_env.py +123 -0
- xgae-0.1.2/templates/custom_tool_prompt_template.txt +25 -0
- xgae-0.1.2/templates/gemini_system_prompt_template.txt +1742 -0
- xgae-0.1.2/templates/general_tool_prompt_template.txt +25 -0
- xgae-0.1.2/templates/scp_test_prompt.txt +21 -0
- xgae-0.1.2/templates/system_prompt_response_sample.txt +1252 -0
- xgae-0.1.2/templates/system_prompt_template.txt +1106 -0
- xgae-0.1.1/src/xgae/engine/xga_engine.py +0 -69
- xgae-0.1.1/src/xgae/engine/xga_prompt_builder.py +0 -38
- xgae-0.1.1/src/xgae/utils/setup_env.py +0 -108
- {xgae-0.1.1 → xgae-0.1.2}/.env +0 -0
- {xgae-0.1.1 → xgae-0.1.2}/.idea/.gitignore +0 -0
- {xgae-0.1.1 → xgae-0.1.2}/.idea/inspectionProfiles/Project_Default.xml +0 -0
- {xgae-0.1.1 → xgae-0.1.2}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
- {xgae-0.1.1 → xgae-0.1.2}/.idea/modules.xml +0 -0
- {xgae-0.1.1 → xgae-0.1.2}/.idea/vcs.xml +0 -0
- {xgae-0.1.1 → xgae-0.1.2}/.python-version +0 -0
- {xgae-0.1.1 → xgae-0.1.2}/README.md +0 -0
- {xgae-0.1.1 → xgae-0.1.2}/mcpservers/custom_servers.json +0 -0
- {xgae-0.1.1 → xgae-0.1.2}/mcpservers/xga_server.json +0 -0
- {xgae-0.1.1 → xgae-0.1.2}/src/xgae/__init__.py +0 -0
- {xgae-0.1.1 → xgae-0.1.2}/src/xgae/engine/responser/xga_non_stream_responser.py +0 -0
- {xgae-0.1.1 → xgae-0.1.2}/src/xgae/engine/responser/xga_responser_utils.py +0 -0
- {xgae-0.1.1 → xgae-0.1.2}/src/xgae/engine/responser/xga_stream_reponser.py +0 -0
- {xgae-0.1.1 → xgae-0.1.2}/uv.lock +0 -0
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
<component name="Black">
|
|
4
4
|
<option name="sdkName" value="Python 3.13 (xgae)" />
|
|
5
5
|
</component>
|
|
6
|
-
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 virtualenv at ~/
|
|
6
|
+
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 virtualenv at ~/DevProjects/xga/xgae/.venv" project-jdk-type="Python SDK" />
|
|
7
7
|
</project>
|
|
@@ -29,16 +29,20 @@
|
|
|
29
29
|
"keyToString": {
|
|
30
30
|
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
|
31
31
|
"Python.llm_client.executor": "Run",
|
|
32
|
+
"Python.run_xga_engine.executor": "Debug",
|
|
33
|
+
"Python.setup_env.executor": "Run",
|
|
32
34
|
"Python.utils.executor": "Run",
|
|
33
|
-
"Python.
|
|
35
|
+
"Python.xga_engine.executor": "Run",
|
|
36
|
+
"Python.xga_mcp_tool_box.executor": "Debug",
|
|
37
|
+
"Python.xga_prompt_builder.executor": "Debug",
|
|
34
38
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
35
|
-
"last_opened_file_path": "/Users/
|
|
39
|
+
"last_opened_file_path": "/Users/sharkystar/DevProjects/xga/xgae",
|
|
36
40
|
"node.js.detected.package.eslint": "true",
|
|
37
41
|
"node.js.detected.package.tslint": "true",
|
|
38
42
|
"node.js.selected.package.eslint": "(autodetect)",
|
|
39
43
|
"node.js.selected.package.tslint": "(autodetect)",
|
|
40
44
|
"nodejs_package_manager_path": "npm",
|
|
41
|
-
"settings.editor.selected.configurable": "
|
|
45
|
+
"settings.editor.selected.configurable": "com.intellij.pycharm.community.ide.impl.configuration.PythonContentEntriesConfigurable",
|
|
42
46
|
"vue.rearranger.settings.migration": "true"
|
|
43
47
|
}
|
|
44
48
|
}</component>
|
|
@@ -57,6 +61,7 @@
|
|
|
57
61
|
<env name="PYTHONUNBUFFERED" value="1" />
|
|
58
62
|
</envs>
|
|
59
63
|
<option name="SDK_HOME" value="" />
|
|
64
|
+
<option name="SDK_NAME" value="Python 3.13 virtualenv at ~/DevProjects/xga/xgae/.venv" />
|
|
60
65
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
61
66
|
<option name="IS_MODULE_SDK" value="false" />
|
|
62
67
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
@@ -81,6 +86,39 @@
|
|
|
81
86
|
<option name="INPUT_FILE" value="" />
|
|
82
87
|
<method v="2" />
|
|
83
88
|
</configuration>
|
|
89
|
+
<configuration name="run_xga_engine" type="PythonConfigurationType" factoryName="Python">
|
|
90
|
+
<module name="xgae" />
|
|
91
|
+
<option name="ENV_FILES" value="" />
|
|
92
|
+
<option name="INTERPRETER_OPTIONS" value="" />
|
|
93
|
+
<option name="PARENT_ENVS" value="true" />
|
|
94
|
+
<envs>
|
|
95
|
+
<env name="PYTHONUNBUFFERED" value="1" />
|
|
96
|
+
</envs>
|
|
97
|
+
<option name="SDK_HOME" value="" />
|
|
98
|
+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
99
|
+
<option name="IS_MODULE_SDK" value="true" />
|
|
100
|
+
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
101
|
+
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
102
|
+
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
|
103
|
+
<EXTENSION ID="net.ashald.envfile">
|
|
104
|
+
<option name="IS_ENABLED" value="false" />
|
|
105
|
+
<option name="IS_SUBST" value="false" />
|
|
106
|
+
<option name="IS_PATH_MACRO_SUPPORTED" value="false" />
|
|
107
|
+
<option name="IS_IGNORE_MISSING_FILES" value="false" />
|
|
108
|
+
<option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false" />
|
|
109
|
+
<ENTRIES>
|
|
110
|
+
<ENTRY IS_ENABLED="true" PARSER="runconfig" IS_EXECUTABLE="false" />
|
|
111
|
+
</ENTRIES>
|
|
112
|
+
</EXTENSION>
|
|
113
|
+
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/xgae/engine/xga_engine.py" />
|
|
114
|
+
<option name="PARAMETERS" value="" />
|
|
115
|
+
<option name="SHOW_COMMAND_LINE" value="false" />
|
|
116
|
+
<option name="EMULATE_TERMINAL" value="false" />
|
|
117
|
+
<option name="MODULE_MODE" value="false" />
|
|
118
|
+
<option name="REDIRECT_INPUT" value="false" />
|
|
119
|
+
<option name="INPUT_FILE" value="" />
|
|
120
|
+
<method v="2" />
|
|
121
|
+
</configuration>
|
|
84
122
|
</component>
|
|
85
123
|
<component name="SharedIndexes">
|
|
86
124
|
<attachedChunks>
|
|
@@ -104,25 +142,37 @@
|
|
|
104
142
|
<workItem from="1755270285722" duration="12068000" />
|
|
105
143
|
<workItem from="1755283728206" duration="1511000" />
|
|
106
144
|
<workItem from="1755286552901" duration="3130000" />
|
|
107
|
-
<workItem from="
|
|
108
|
-
<workItem from="
|
|
109
|
-
<workItem from="
|
|
110
|
-
<workItem from="
|
|
111
|
-
<workItem from="
|
|
112
|
-
<workItem from="
|
|
113
|
-
<workItem from="
|
|
114
|
-
<workItem from="1755419142521" duration="150000" />
|
|
115
|
-
<workItem from="1755429851003" duration="290000" />
|
|
116
|
-
<workItem from="1755430331676" duration="21000" />
|
|
145
|
+
<workItem from="1755409529770" duration="670000" />
|
|
146
|
+
<workItem from="1755478595168" duration="20000" />
|
|
147
|
+
<workItem from="1755479257156" duration="16895000" />
|
|
148
|
+
<workItem from="1755525531052" duration="13030000" />
|
|
149
|
+
<workItem from="1755585869510" duration="5796000" />
|
|
150
|
+
<workItem from="1755593112104" duration="786000" />
|
|
151
|
+
<workItem from="1755611972189" duration="671000" />
|
|
117
152
|
</task>
|
|
118
153
|
<servers />
|
|
119
154
|
</component>
|
|
120
155
|
<component name="TypeScriptGeneratedFilesManager">
|
|
121
156
|
<option name="version" value="3" />
|
|
122
157
|
</component>
|
|
158
|
+
<component name="XDebuggerManager">
|
|
159
|
+
<breakpoint-manager>
|
|
160
|
+
<default-breakpoints>
|
|
161
|
+
<breakpoint type="python-exception">
|
|
162
|
+
<properties notifyOnTerminate="true" exception="BaseException">
|
|
163
|
+
<option name="notifyOnTerminate" value="true" />
|
|
164
|
+
</properties>
|
|
165
|
+
</breakpoint>
|
|
166
|
+
</default-breakpoints>
|
|
167
|
+
</breakpoint-manager>
|
|
168
|
+
</component>
|
|
123
169
|
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
|
124
|
-
<SUITE FILE_PATH="coverage/xgae$
|
|
125
|
-
<SUITE FILE_PATH="coverage/xgae$
|
|
170
|
+
<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$" />
|
|
171
|
+
<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$" />
|
|
172
|
+
<SUITE FILE_PATH="coverage/xgae$run_xga_engine.coverage" NAME="run_xga_engine Coverage Results" MODIFIED="1755593194247" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
126
173
|
<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$" />
|
|
174
|
+
<SUITE FILE_PATH="coverage/xgae$setup_env.coverage" NAME="setup_env Coverage Results" MODIFIED="1755565531587" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
175
|
+
<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$" />
|
|
176
|
+
<SUITE FILE_PATH="coverage/xgae$llm_client.coverage" NAME="llm_client Coverage Results" MODIFIED="1755565705235" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
|
127
177
|
</component>
|
|
128
178
|
</project>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
|
6
6
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
|
7
7
|
</content>
|
|
8
|
-
<orderEntry type="jdk" jdkName="Python 3.13 virtualenv at ~/
|
|
8
|
+
<orderEntry type="jdk" jdkName="Python 3.13 virtualenv at ~/DevProjects/xga/xgae/.venv" jdkType="Python SDK" />
|
|
9
9
|
<orderEntry type="sourceFolder" forTests="false" />
|
|
10
10
|
</component>
|
|
11
11
|
</module>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import List, Any, Dict, Optional, AsyncGenerator
|
|
3
|
+
from uuid import uuid4
|
|
4
|
+
|
|
5
|
+
from xgae.engine.xga_base import XGAMessage, XGAToolSchema, XGAToolBox
|
|
6
|
+
from xgae.utils.llm_client import LLMClient
|
|
7
|
+
from xgae.utils.setup_env import langfuse
|
|
8
|
+
from xga_prompt_builder import XGAPromptBuilder
|
|
9
|
+
from xga_mcp_tool_box import XGAMcpToolBox
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class XGAEngine():
|
|
13
|
+
def __init__(self,
|
|
14
|
+
session_id: Optional[str] = None,
|
|
15
|
+
trace_id: Optional[str] = None,
|
|
16
|
+
agent_id: Optional[str] = None,
|
|
17
|
+
llm_config: Optional[Dict[str, Any]] = None,
|
|
18
|
+
prompt_builder: Optional[XGAPromptBuilder] = None,
|
|
19
|
+
tool_box: Optional[XGAToolBox] = None):
|
|
20
|
+
self.session_id = session_id if session_id else f"xga_sid_{uuid4()}"
|
|
21
|
+
self.agent_id = agent_id
|
|
22
|
+
|
|
23
|
+
self.messages: List[XGAMessage] = []
|
|
24
|
+
self.llm_client = LLMClient(llm_config)
|
|
25
|
+
self.model_name = self.llm_client.model_name
|
|
26
|
+
self.is_stream = self.llm_client.is_stream
|
|
27
|
+
|
|
28
|
+
self.prompt_builder = prompt_builder or XGAPromptBuilder()
|
|
29
|
+
self.tool_box = tool_box or XGAMcpToolBox()
|
|
30
|
+
|
|
31
|
+
self.task_id = None
|
|
32
|
+
self.trace_id = trace_id if trace_id else langfuse.create_trace_id()
|
|
33
|
+
|
|
34
|
+
async def __async_init__(self) -> None:
|
|
35
|
+
await self.tool_box.load_mcp_tools_schema()
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
async def create(cls,
|
|
39
|
+
session_id: Optional[str] = None,
|
|
40
|
+
trace_id: Optional[str] = None,
|
|
41
|
+
agent_id: Optional[str] = None,
|
|
42
|
+
llm_config: Optional[Dict[str, Any]] = None,
|
|
43
|
+
prompt_builder: Optional[XGAPromptBuilder] = None,
|
|
44
|
+
tool_box: Optional[XGAToolBox] = None) -> 'XGAEngine' :
|
|
45
|
+
engine: XGAEngine = cls(session_id=session_id,
|
|
46
|
+
trace_id=trace_id,
|
|
47
|
+
agent_id=agent_id,
|
|
48
|
+
llm_config=llm_config,
|
|
49
|
+
prompt_builder=prompt_builder,
|
|
50
|
+
tool_box=tool_box)
|
|
51
|
+
|
|
52
|
+
await engine.__async_init__()
|
|
53
|
+
return engine
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
async def run_task(self,
|
|
57
|
+
task_messages: List[Dict[str, Any]],
|
|
58
|
+
task_id: Optional[str] = None,
|
|
59
|
+
system_prompt: Optional[str] = None,
|
|
60
|
+
general_tools: Optional[List[str]] = ["*"],
|
|
61
|
+
custom_tools: Optional[List[str]] = []) -> AsyncGenerator:
|
|
62
|
+
try:
|
|
63
|
+
self.task_id = task_id if task_id else f"xga_task_{uuid4()}"
|
|
64
|
+
await self.tool_box.creat_task_tool_box(self.task_id, general_tools, custom_tools)
|
|
65
|
+
task_prompt = self.build_task_prompt(system_prompt)
|
|
66
|
+
yield task_prompt
|
|
67
|
+
|
|
68
|
+
finally:
|
|
69
|
+
await self.tool_box.destroy_task_tool_box(self.task_id)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _run_task_once(self):
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
def build_task_prompt(self, system_prompt: Optional[str] = None) -> str:
|
|
76
|
+
task_prompt = self.prompt_builder.build_system_prompt(self.model_name, system_prompt)
|
|
77
|
+
|
|
78
|
+
tool_schemas =self.tool_box.get_task_tool_schemas(self.task_id, "general_tool")
|
|
79
|
+
tool_prompt = self.prompt_builder.build_general_tool_prompt(tool_schemas)
|
|
80
|
+
task_prompt = task_prompt + "\n" + tool_prompt
|
|
81
|
+
|
|
82
|
+
tool_schemas = self.tool_box.get_task_tool_schemas(self.task_id, "custom_tool")
|
|
83
|
+
tool_prompt = self.prompt_builder.build_custom_tool_prompt(tool_schemas)
|
|
84
|
+
task_prompt = task_prompt + "\n" + tool_prompt
|
|
85
|
+
|
|
86
|
+
return task_prompt
|
|
87
|
+
|
|
88
|
+
def add_message(self, message: XGAMessage):
|
|
89
|
+
message.message_id = f"xga_msg_{uuid4()}"
|
|
90
|
+
message.session_id = self.session_id
|
|
91
|
+
message.agent_id = self.agent_id
|
|
92
|
+
self.messages.append(message)
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
import asyncio
|
|
96
|
+
|
|
97
|
+
async def main():
|
|
98
|
+
#tool_box = XGAMcpToolBox(custom_mcp_server_file="mcpservers/custom_servers.json")
|
|
99
|
+
tool_box = None
|
|
100
|
+
engine = await XGAEngine.create(tool_box=tool_box)
|
|
101
|
+
# async for chunk in engine.run_task(task_messages=[{}], custom_tools=["bomc_fault.*"]):
|
|
102
|
+
async for chunk in engine.run_task(task_messages=[{}], custom_tools=[]):
|
|
103
|
+
print(chunk)
|
|
104
|
+
|
|
105
|
+
asyncio.run(main())
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
|
+
|
|
4
5
|
from typing import List, Any, Dict, Optional, Literal, override
|
|
5
6
|
|
|
6
7
|
from langchain_mcp_adapters.client import MultiServerMCPClient
|
|
@@ -14,8 +15,9 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
14
15
|
GENERAL_MCP_SERVER_NAME = "xga_general"
|
|
15
16
|
|
|
16
17
|
def __init__(self,
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
custom_mcp_server_file: Optional[str] = None,
|
|
19
|
+
custom_mcp_server_config: Optional[Dict[str, Any]] = None
|
|
20
|
+
):
|
|
19
21
|
general_mcp_server_config = self._load_mcp_servers_config("mcpservers/xga_server.json")
|
|
20
22
|
tool_box_mcp_server_config = general_mcp_server_config.get("mcpServers", {})
|
|
21
23
|
|
|
@@ -31,6 +33,8 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
31
33
|
self.mcp_tool_schemas: Dict[str, List[XGAToolSchema]] = {}
|
|
32
34
|
self.task_tool_schemas: Dict[str, Dict[str,XGAToolSchema]] = {}
|
|
33
35
|
|
|
36
|
+
self.is_loaded_tool_schemas = False
|
|
37
|
+
|
|
34
38
|
@override
|
|
35
39
|
async def creat_task_tool_box(self, task_id: str, general_tools: List[str], custom_tools: List[str]):
|
|
36
40
|
task_tool_schemas = {}
|
|
@@ -41,7 +45,7 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
41
45
|
for tool_schema in general_tool_schemas:
|
|
42
46
|
if tool_schema.tool_name in general_tools:
|
|
43
47
|
task_tool_schemas[tool_schema.tool_name] = tool_schema
|
|
44
|
-
task_tool_schemas.pop("end_task")
|
|
48
|
+
task_tool_schemas.pop("end_task", None)
|
|
45
49
|
|
|
46
50
|
for server_tool_name in custom_tools:
|
|
47
51
|
parts = server_tool_name.split(".")
|
|
@@ -122,20 +126,35 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
122
126
|
|
|
123
127
|
return result
|
|
124
128
|
|
|
129
|
+
|
|
125
130
|
async def load_mcp_tools_schema(self)-> None:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
input_schema =
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
131
|
+
if not self.is_loaded_tool_schemas:
|
|
132
|
+
for server_name in self.mcp_server_names:
|
|
133
|
+
self.mcp_tool_schemas[server_name] = []
|
|
134
|
+
mcp_tools = await self._mcp_client.get_tools(server_name=server_name)
|
|
135
|
+
|
|
136
|
+
for tool in mcp_tools:
|
|
137
|
+
input_schema = tool.args_schema
|
|
138
|
+
if server_name == self.GENERAL_MCP_SERVER_NAME:
|
|
139
|
+
input_schema['properties'].pop("task_id", None)
|
|
140
|
+
if 'task_id' in input_schema['required']:
|
|
141
|
+
input_schema['required'].remove('task_id')
|
|
142
|
+
params_properties = input_schema.get("properties", {})
|
|
143
|
+
for param_properties in params_properties.values():
|
|
144
|
+
param_properties.pop("title", None)
|
|
145
|
+
|
|
146
|
+
metadata = tool.metadata or {}
|
|
147
|
+
tool_schema = XGAToolSchema(tool_name=tool.name,
|
|
148
|
+
server_name=server_name,
|
|
149
|
+
description=tool.description,
|
|
150
|
+
input_schema=input_schema,
|
|
151
|
+
metadata=metadata)
|
|
152
|
+
self.mcp_tool_schemas[server_name].append(tool_schema)
|
|
153
|
+
self.is_loaded_tool_schemas = True
|
|
154
|
+
|
|
155
|
+
async def reload_mcp_tools_schema(self) -> None:
|
|
156
|
+
self.is_loaded_tool_schemas = False
|
|
157
|
+
await self.load_mcp_tools_schema()
|
|
139
158
|
|
|
140
159
|
@staticmethod
|
|
141
160
|
def _load_mcp_servers_config(mcp_config_path: str) -> Dict[str, Any]:
|
|
@@ -164,10 +183,11 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
164
183
|
if __name__ == "__main__":
|
|
165
184
|
import asyncio
|
|
166
185
|
from dataclasses import asdict
|
|
186
|
+
|
|
167
187
|
async def main():
|
|
168
188
|
task_id = "task1"
|
|
169
|
-
mcp_tool_box = XGAMcpToolBox(custom_mcp_server_file="mcpservers/custom_servers.json")
|
|
170
|
-
|
|
189
|
+
#mcp_tool_box = XGAMcpToolBox(custom_mcp_server_file="mcpservers/custom_servers.json")
|
|
190
|
+
mcp_tool_box = XGAMcpToolBox()
|
|
171
191
|
await mcp_tool_box.load_mcp_tools_schema()
|
|
172
192
|
await mcp_tool_box.creat_task_tool_box(task_id=task_id, general_tools=["*"], custom_tools=["bomc_fault.*"])
|
|
173
193
|
tool_schemas = mcp_tool_box.get_task_tool_schemas(task_id, "general_tool")
|
|
@@ -189,4 +209,5 @@ if __name__ == "__main__":
|
|
|
189
209
|
print(f"call complete result: {result}")
|
|
190
210
|
|
|
191
211
|
await mcp_tool_box.destroy_task_tool_box(task_id)
|
|
212
|
+
|
|
192
213
|
asyncio.run(main())
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import sys
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
from typing import Optional, List
|
|
6
|
+
from io import StringIO
|
|
7
|
+
|
|
8
|
+
from xga_base import XGAToolSchema
|
|
9
|
+
from xgae.utils.setup_env import read_file, XGAError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class XGAPromptBuilder():
|
|
13
|
+
def __init__(self, system_prompt_template: Optional[str] = None):
|
|
14
|
+
self.system_prompt = None
|
|
15
|
+
if system_prompt_template:
|
|
16
|
+
self.system_prompt = system_prompt_template
|
|
17
|
+
|
|
18
|
+
def build_system_prompt(self, model_name: str, system_prompt: Optional[str]=None)-> str:
|
|
19
|
+
task_system_prompt = system_prompt if system_prompt else self.system_prompt
|
|
20
|
+
if task_system_prompt is None:
|
|
21
|
+
task_system_prompt = self._load_default_system_prompt(model_name)
|
|
22
|
+
return task_system_prompt
|
|
23
|
+
|
|
24
|
+
def build_general_tool_prompt(self, tool_schemas:List[XGAToolSchema])-> str:
|
|
25
|
+
tool_prompt = ""
|
|
26
|
+
tool_schemas = tool_schemas or []
|
|
27
|
+
if len(tool_schemas) > 0:
|
|
28
|
+
tool_prompt = read_file("templates/general_tool_prompt_template.txt")
|
|
29
|
+
example_prompt = ""
|
|
30
|
+
openai_schemas = []
|
|
31
|
+
for tool_schema in tool_schemas:
|
|
32
|
+
openai_schema = {}
|
|
33
|
+
openai_schema["type"] = "function"
|
|
34
|
+
openai_function = {}
|
|
35
|
+
openai_schema["function"] = openai_function
|
|
36
|
+
|
|
37
|
+
openai_function["name"] = tool_schema.tool_name
|
|
38
|
+
openai_function["description"] = tool_schema.description if tool_schema.description else 'No description available'
|
|
39
|
+
|
|
40
|
+
openai_parameters = {}
|
|
41
|
+
input_schema = tool_schema.input_schema
|
|
42
|
+
openai_function["parameters"] = openai_parameters
|
|
43
|
+
openai_parameters["type"] = input_schema["type"]
|
|
44
|
+
openai_parameters["properties"] = input_schema.get("properties", [])
|
|
45
|
+
openai_parameters["required"] = input_schema["required"]
|
|
46
|
+
|
|
47
|
+
openai_schemas.append(openai_schema)
|
|
48
|
+
|
|
49
|
+
metadata = tool_schema.metadata or {}
|
|
50
|
+
example = metadata.get("example", None)
|
|
51
|
+
if example:
|
|
52
|
+
example_prompt += f"\n{example}\n"
|
|
53
|
+
|
|
54
|
+
schema_prompt = json.dumps(openai_schemas, ensure_ascii=False, indent=2)
|
|
55
|
+
tool_prompt = tool_prompt.format(tool_schemas=schema_prompt, tool_examples=example_prompt)
|
|
56
|
+
return tool_prompt
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def build_custom_tool_prompt(self, tool_schemas:List[XGAToolSchema])-> str:
|
|
60
|
+
tool_prompt = ""
|
|
61
|
+
tool_schemas = tool_schemas or []
|
|
62
|
+
if len(tool_schemas) > 0:
|
|
63
|
+
tool_prompt = read_file("templates/custom_tool_prompt_template.txt")
|
|
64
|
+
tool_info = ""
|
|
65
|
+
for tool_schema in tool_schemas:
|
|
66
|
+
description = tool_schema.description if tool_schema.description else 'No description available'
|
|
67
|
+
tool_info += f"- **{tool_schema.tool_name}**: {description}\n"
|
|
68
|
+
tool_info += f" Parameters: {tool_schema.input_schema}\n"
|
|
69
|
+
tool_prompt = tool_prompt.replace("{tool_schemas}", tool_info)
|
|
70
|
+
|
|
71
|
+
return tool_prompt
|
|
72
|
+
|
|
73
|
+
def _load_default_system_prompt(self, model_name) -> Optional[str]:
|
|
74
|
+
if "gemini-2.5-flash" in model_name.lower() and "gemini-2.5-pro" not in model_name.lower():
|
|
75
|
+
org_prompt_template = read_file("templates/gemini_system_prompt_template.txt")
|
|
76
|
+
else:
|
|
77
|
+
org_prompt_template = read_file("templates/system_prompt_template.txt")
|
|
78
|
+
|
|
79
|
+
original_stdout = sys.stdout
|
|
80
|
+
buffer = StringIO()
|
|
81
|
+
sys.stdout = buffer
|
|
82
|
+
try:
|
|
83
|
+
namespace = {
|
|
84
|
+
"datetime": datetime,
|
|
85
|
+
"__builtins__": __builtins__
|
|
86
|
+
}
|
|
87
|
+
code = f"print(f\"\"\"{org_prompt_template}\"\"\")"
|
|
88
|
+
exec(code, namespace)
|
|
89
|
+
system_prompt_template = buffer.getvalue()
|
|
90
|
+
finally:
|
|
91
|
+
sys.stdout = original_stdout
|
|
92
|
+
|
|
93
|
+
system_prompt = system_prompt_template.format(
|
|
94
|
+
current_date=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d'),
|
|
95
|
+
current_time=datetime.datetime.now(datetime.timezone.utc).strftime('%H:%M:%S'),
|
|
96
|
+
current_year=datetime.datetime.now(datetime.timezone.utc).strftime('%Y')
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
if "anthropic" not in model_name.lower():
|
|
100
|
+
sample_response = read_file("templates/system_prompt_response_sample.txt")
|
|
101
|
+
system_prompt = system_prompt + "\n\n <sample_assistant_response>" + sample_response + "</sample_assistant_response>"
|
|
102
|
+
|
|
103
|
+
return system_prompt
|
|
104
|
+
|
|
105
|
+
if __name__ == "__main__":
|
|
106
|
+
|
|
107
|
+
prompt_builder = XGAPromptBuilder()
|
|
108
|
+
prompt = prompt_builder.build_system_prompt("openai/qwen3-235b-a22b")
|
|
109
|
+
|
|
110
|
+
# system_prompt = read_file("templates/scp_test_prompt.txt")
|
|
111
|
+
# prompt = prompt_builder.build_system_prompt("openai/qwen3-235b-a22b", system_prompt=system_prompt)
|
|
112
|
+
|
|
113
|
+
print(prompt)
|
|
114
|
+
|
|
115
|
+
|
|
@@ -9,8 +9,6 @@ from typing import Union, Dict, Any, Optional, List
|
|
|
9
9
|
from litellm.utils import ModelResponse, CustomStreamWrapper
|
|
10
10
|
from openai import OpenAIError
|
|
11
11
|
|
|
12
|
-
from setup_env import setup_xga_env
|
|
13
|
-
|
|
14
12
|
|
|
15
13
|
class LLMError(Exception):
|
|
16
14
|
"""Base exception for LLM-related errors."""
|
|
@@ -20,7 +18,7 @@ class LLMClient:
|
|
|
20
18
|
RATE_LIMIT_DELAY = 30
|
|
21
19
|
RETRY_DELAY = 0.1
|
|
22
20
|
|
|
23
|
-
def __init__(self, llm_config: Optional[Dict[str, Any]]=
|
|
21
|
+
def __init__(self, llm_config: Optional[Dict[str, Any]]=None) -> None:
|
|
24
22
|
"""
|
|
25
23
|
Arg: llm_config (Optional[Dict[str, Any]], optional)
|
|
26
24
|
model: Override default model to use, default set by .env LLM_MODEL
|
|
@@ -36,6 +34,7 @@ class LLMClient:
|
|
|
36
34
|
reasoning_effort: Optional level of reasoning effort, default is ‘low’
|
|
37
35
|
top_p: Optional Top-p sampling parameter, default is None
|
|
38
36
|
"""
|
|
37
|
+
llm_config = llm_config or {}
|
|
39
38
|
litellm.modify_params = True
|
|
40
39
|
litellm.drop_params = True
|
|
41
40
|
|
|
@@ -214,8 +213,6 @@ class LLMClient:
|
|
|
214
213
|
raise LLMError(f"LLM completion failed after {self.max_retries} attempts !")
|
|
215
214
|
|
|
216
215
|
if __name__ == "__main__":
|
|
217
|
-
setup_xga_env()
|
|
218
|
-
|
|
219
216
|
async def llm_completion():
|
|
220
217
|
llm_client = LLMClient({
|
|
221
218
|
"stream": False #default is True
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import traceback
|
|
4
|
+
|
|
5
|
+
from langfuse import Langfuse
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
_log_initialized = False
|
|
9
|
+
|
|
10
|
+
def setup_logging() -> None:
|
|
11
|
+
global _log_initialized
|
|
12
|
+
if not _log_initialized:
|
|
13
|
+
import colorlog
|
|
14
|
+
from dotenv import load_dotenv
|
|
15
|
+
load_dotenv()
|
|
16
|
+
|
|
17
|
+
env_log_level = os.getenv("LOG_LEVEL", "INFO")
|
|
18
|
+
env_log_file = os.getenv("LOG_FILE", "log/xga.log")
|
|
19
|
+
log_level = getattr(logging, env_log_level.upper(), logging.INFO)
|
|
20
|
+
|
|
21
|
+
log_dir = os.path.dirname(env_log_file)
|
|
22
|
+
if log_dir and not os.path.exists(log_dir):
|
|
23
|
+
os.makedirs(log_dir, exist_ok=True)
|
|
24
|
+
else:
|
|
25
|
+
os.remove(env_log_file)
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger()
|
|
28
|
+
for handler in logger.handlers[:]:
|
|
29
|
+
logger.removeHandler(handler)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
log_colors = {
|
|
34
|
+
'DEBUG': 'cyan',
|
|
35
|
+
'INFO': 'green',
|
|
36
|
+
'WARNING': 'yellow',
|
|
37
|
+
'ERROR': 'red',
|
|
38
|
+
'CRITICAL': 'red,bg_white'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console_formatter = colorlog.ColoredFormatter('%(log_color)s%(asctime)s - %(levelname)-8s%(reset)s %(white)s%(message)s',
|
|
42
|
+
log_colors=log_colors,
|
|
43
|
+
datefmt='%Y-%m-%d %H:%M:%S'
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
file_formatter = logging.Formatter(
|
|
47
|
+
'%(asctime)s -%(levelname)-8s %(message)s',
|
|
48
|
+
datefmt='%Y-%m-%d %H:%M:%S'
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
console_handler = logging.StreamHandler()
|
|
52
|
+
console_handler.setFormatter(console_formatter)
|
|
53
|
+
|
|
54
|
+
file_handler = logging.FileHandler(env_log_file, encoding='utf-8')
|
|
55
|
+
file_handler.setFormatter(file_formatter)
|
|
56
|
+
|
|
57
|
+
logger.addHandler(console_handler)
|
|
58
|
+
logger.addHandler(file_handler)
|
|
59
|
+
|
|
60
|
+
logger.setLevel(log_level)
|
|
61
|
+
|
|
62
|
+
logging.info(f"Logger is initialized, log_level={env_log_level}, log_file={env_log_file}")
|
|
63
|
+
|
|
64
|
+
_log_initialized = True
|
|
65
|
+
|
|
66
|
+
setup_logging()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class XGAError(Exception):
|
|
70
|
+
"""Custom exception for errors in the XGA system."""
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
def handle_error(e: Exception) -> None:
|
|
74
|
+
logging.error("An error occurred: %s", str(e))
|
|
75
|
+
logging.error("Traceback details:\n%s", traceback.format_exc())
|
|
76
|
+
raise (e) from e
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
_langfuse_initialized = False
|
|
80
|
+
|
|
81
|
+
def setup_langfuse() -> Langfuse:
|
|
82
|
+
global _langfuse_initialized
|
|
83
|
+
_langfuse = None
|
|
84
|
+
if not _langfuse_initialized:
|
|
85
|
+
env_public_key = os.getenv("LANGFUSE_PUBLIC_KEY")
|
|
86
|
+
env_secret_key = os.getenv("LANGFUSE_SECRET_KEY")
|
|
87
|
+
env_host = os.getenv("LANGFUSE_HOST", "https://cloud.langfuse.com")
|
|
88
|
+
if env_public_key and env_secret_key:
|
|
89
|
+
_langfuse = Langfuse(tracing_enabled=True,
|
|
90
|
+
public_key=env_public_key,
|
|
91
|
+
secret_key=env_secret_key,
|
|
92
|
+
host=env_host)
|
|
93
|
+
logging.info("Langfuse initialized Successfully by Key !")
|
|
94
|
+
else:
|
|
95
|
+
_langfuse = Langfuse(tracing_enabled=False)
|
|
96
|
+
logging.warning("Not set key, Langfuse is disabled!")
|
|
97
|
+
|
|
98
|
+
_langfuse_initialized = True
|
|
99
|
+
return _langfuse
|
|
100
|
+
|
|
101
|
+
langfuse: Langfuse = Langfuse if _langfuse_initialized else setup_langfuse()
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def read_file(file_path: str) -> str:
|
|
105
|
+
if not os.path.exists(file_path):
|
|
106
|
+
logging.error(f"File '{file_path}' not found")
|
|
107
|
+
raise XGAError(f"File '{file_path}' not found")
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
with open(file_path, "r", encoding="utf-8") as template_file:
|
|
111
|
+
content = template_file.read()
|
|
112
|
+
return content
|
|
113
|
+
except Exception as e:
|
|
114
|
+
logging.error(f"Read file '{file_path}' failed")
|
|
115
|
+
handle_error(e)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
if __name__ == "__main__":
|
|
119
|
+
try:
|
|
120
|
+
trace_id = langfuse.create_trace_id()
|
|
121
|
+
print(f"trace_id={trace_id}")
|
|
122
|
+
except Exception as e:
|
|
123
|
+
handle_error(e)
|