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.

Files changed (35) hide show
  1. {xgae-0.1.1 → xgae-0.1.2}/.idea/misc.xml +1 -1
  2. {xgae-0.1.1 → xgae-0.1.2}/.idea/workspace.xml +65 -15
  3. {xgae-0.1.1 → xgae-0.1.2}/.idea/xgae.iml +1 -1
  4. {xgae-0.1.1 → xgae-0.1.2}/PKG-INFO +1 -1
  5. {xgae-0.1.1 → xgae-0.1.2}/pyproject.toml +1 -1
  6. {xgae-0.1.1 → xgae-0.1.2}/src/xgae/engine/xga_base.py +2 -1
  7. xgae-0.1.2/src/xgae/engine/xga_engine.py +105 -0
  8. {xgae-0.1.1 → xgae-0.1.2}/src/xgae/engine/xga_mcp_tool_box.py +39 -18
  9. xgae-0.1.2/src/xgae/engine/xga_prompt_builder.py +115 -0
  10. {xgae-0.1.1 → xgae-0.1.2}/src/xgae/utils/llm_client.py +2 -5
  11. xgae-0.1.2/src/xgae/utils/setup_env.py +123 -0
  12. xgae-0.1.2/templates/custom_tool_prompt_template.txt +25 -0
  13. xgae-0.1.2/templates/gemini_system_prompt_template.txt +1742 -0
  14. xgae-0.1.2/templates/general_tool_prompt_template.txt +25 -0
  15. xgae-0.1.2/templates/scp_test_prompt.txt +21 -0
  16. xgae-0.1.2/templates/system_prompt_response_sample.txt +1252 -0
  17. xgae-0.1.2/templates/system_prompt_template.txt +1106 -0
  18. xgae-0.1.1/src/xgae/engine/xga_engine.py +0 -69
  19. xgae-0.1.1/src/xgae/engine/xga_prompt_builder.py +0 -38
  20. xgae-0.1.1/src/xgae/utils/setup_env.py +0 -108
  21. {xgae-0.1.1 → xgae-0.1.2}/.env +0 -0
  22. {xgae-0.1.1 → xgae-0.1.2}/.idea/.gitignore +0 -0
  23. {xgae-0.1.1 → xgae-0.1.2}/.idea/inspectionProfiles/Project_Default.xml +0 -0
  24. {xgae-0.1.1 → xgae-0.1.2}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
  25. {xgae-0.1.1 → xgae-0.1.2}/.idea/modules.xml +0 -0
  26. {xgae-0.1.1 → xgae-0.1.2}/.idea/vcs.xml +0 -0
  27. {xgae-0.1.1 → xgae-0.1.2}/.python-version +0 -0
  28. {xgae-0.1.1 → xgae-0.1.2}/README.md +0 -0
  29. {xgae-0.1.1 → xgae-0.1.2}/mcpservers/custom_servers.json +0 -0
  30. {xgae-0.1.1 → xgae-0.1.2}/mcpservers/xga_server.json +0 -0
  31. {xgae-0.1.1 → xgae-0.1.2}/src/xgae/__init__.py +0 -0
  32. {xgae-0.1.1 → xgae-0.1.2}/src/xgae/engine/responser/xga_non_stream_responser.py +0 -0
  33. {xgae-0.1.1 → xgae-0.1.2}/src/xgae/engine/responser/xga_responser_utils.py +0 -0
  34. {xgae-0.1.1 → xgae-0.1.2}/src/xgae/engine/responser/xga_stream_reponser.py +0 -0
  35. {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 ~/DevelopSpace/xgae/.venv" project-jdk-type="Python SDK" />
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
  &quot;keyToString&quot;: {
30
30
  &quot;ModuleVcsDetector.initialDetectionPerformed&quot;: &quot;true&quot;,
31
31
  &quot;Python.llm_client.executor&quot;: &quot;Run&quot;,
32
+ &quot;Python.run_xga_engine.executor&quot;: &quot;Debug&quot;,
33
+ &quot;Python.setup_env.executor&quot;: &quot;Run&quot;,
32
34
  &quot;Python.utils.executor&quot;: &quot;Run&quot;,
33
- &quot;Python.xga_mcp_tool_box.executor&quot;: &quot;Run&quot;,
35
+ &quot;Python.xga_engine.executor&quot;: &quot;Run&quot;,
36
+ &quot;Python.xga_mcp_tool_box.executor&quot;: &quot;Debug&quot;,
37
+ &quot;Python.xga_prompt_builder.executor&quot;: &quot;Debug&quot;,
34
38
  &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
35
- &quot;last_opened_file_path&quot;: &quot;/Users/goosezzy/DevelopSpace/xgae&quot;,
39
+ &quot;last_opened_file_path&quot;: &quot;/Users/sharkystar/DevProjects/xga/xgae&quot;,
36
40
  &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
37
41
  &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
38
42
  &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
39
43
  &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
40
44
  &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
41
- &quot;settings.editor.selected.configurable&quot;: &quot;preferences.general&quot;,
45
+ &quot;settings.editor.selected.configurable&quot;: &quot;com.intellij.pycharm.community.ide.impl.configuration.PythonContentEntriesConfigurable&quot;,
42
46
  &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
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="1755307767865" duration="337000" />
108
- <workItem from="1755308113420" duration="2825000" />
109
- <workItem from="1755321931380" duration="8531000" />
110
- <workItem from="1755330830188" duration="229000" />
111
- <workItem from="1755396985976" duration="6435000" />
112
- <workItem from="1755415614018" duration="461000" />
113
- <workItem from="1755416476555" duration="256000" />
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$xga_mcp_tool_box.coverage" NAME="xga_mcp_tool_box Coverage Results" MODIFIED="1755430037796" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
125
- <SUITE FILE_PATH="coverage/xgae$llm_client.coverage" NAME="llm_client Coverage Results" MODIFIED="1755247632274" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
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 ~/DevelopSpace/xgae/.venv" jdkType="Python SDK" />
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>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xgae
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Extreme General Agent Engine
5
5
  Requires-Python: >=3.13
6
6
  Requires-Dist: colorlog>=6.9.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "xgae"
3
- version = "0.1.1"
3
+ version = "0.1.2"
4
4
  description = "Extreme General Agent Engine"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"
@@ -20,7 +20,8 @@ class XGAToolSchema:
20
20
  tool_name: str
21
21
  server_name: str
22
22
  description: str
23
- input_schema: Optional[str]
23
+ input_schema: Dict[str, Any]
24
+ metadata: Optional[Dict[str, Any]]
24
25
 
25
26
 
26
27
  @dataclass
@@ -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
- custom_mcp_server_config: Optional[Dict[str, Any]] = None,
18
- custom_mcp_server_file: Optional[str] = None):
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
- for server_name in self.mcp_server_names:
127
- self.mcp_tool_schemas[server_name] = []
128
- mcp_tools = await self._mcp_client.get_tools(server_name=server_name)
129
- for tool in mcp_tools:
130
- input_schema = tool.args_schema
131
- if server_name == self.GENERAL_MCP_SERVER_NAME:
132
- input_schema = str(tool.args_schema) # @todo remove task_id param
133
- input_schema_str = str(input_schema) # @todo convert input tool.args_schema
134
- tool_schema = XGAToolSchema(tool_name=tool.name,
135
- server_name=server_name,
136
- description=tool.description,
137
- input_schema=input_schema_str)
138
- self.mcp_tool_schemas[server_name].append(tool_schema)
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
- #mcp_tool_box = XGAMcpToolBox()
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]]={}) -> None:
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)