xgae 0.1.1__tar.gz → 0.1.3__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 (36) hide show
  1. {xgae-0.1.1 → xgae-0.1.3}/.idea/misc.xml +1 -1
  2. {xgae-0.1.1 → xgae-0.1.3}/.idea/workspace.xml +78 -28
  3. {xgae-0.1.1 → xgae-0.1.3}/.idea/xgae.iml +1 -1
  4. {xgae-0.1.1 → xgae-0.1.3}/PKG-INFO +1 -1
  5. {xgae-0.1.1 → xgae-0.1.3}/pyproject.toml +1 -1
  6. {xgae-0.1.1 → xgae-0.1.3}/src/xgae/engine/xga_base.py +5 -2
  7. xgae-0.1.3/src/xgae/engine/xga_engine.py +99 -0
  8. {xgae-0.1.1 → xgae-0.1.3}/src/xgae/engine/xga_mcp_tool_box.py +41 -21
  9. xgae-0.1.3/src/xgae/engine/xga_prompt_builder.py +97 -0
  10. {xgae-0.1.1 → xgae-0.1.3}/src/xgae/utils/llm_client.py +2 -5
  11. xgae-0.1.3/src/xgae/utils/setup_env.py +96 -0
  12. xgae-0.1.3/src/xgae/utils/utils.py +42 -0
  13. xgae-0.1.3/templates/custom_tool_prompt_template.txt +25 -0
  14. xgae-0.1.3/templates/gemini_system_prompt_template.txt +1742 -0
  15. xgae-0.1.3/templates/general_tool_prompt_template.txt +25 -0
  16. xgae-0.1.3/templates/scp_test_prompt.txt +21 -0
  17. xgae-0.1.3/templates/system_prompt_response_sample.txt +1252 -0
  18. xgae-0.1.3/templates/system_prompt_template.txt +1106 -0
  19. xgae-0.1.1/src/xgae/engine/xga_engine.py +0 -69
  20. xgae-0.1.1/src/xgae/engine/xga_prompt_builder.py +0 -38
  21. xgae-0.1.1/src/xgae/utils/setup_env.py +0 -108
  22. {xgae-0.1.1 → xgae-0.1.3}/.env +0 -0
  23. {xgae-0.1.1 → xgae-0.1.3}/.idea/.gitignore +0 -0
  24. {xgae-0.1.1 → xgae-0.1.3}/.idea/inspectionProfiles/Project_Default.xml +0 -0
  25. {xgae-0.1.1 → xgae-0.1.3}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
  26. {xgae-0.1.1 → xgae-0.1.3}/.idea/modules.xml +0 -0
  27. {xgae-0.1.1 → xgae-0.1.3}/.idea/vcs.xml +0 -0
  28. {xgae-0.1.1 → xgae-0.1.3}/.python-version +0 -0
  29. {xgae-0.1.1 → xgae-0.1.3}/README.md +0 -0
  30. {xgae-0.1.1 → xgae-0.1.3}/mcpservers/custom_servers.json +0 -0
  31. {xgae-0.1.1 → xgae-0.1.3}/mcpservers/xga_server.json +0 -0
  32. {xgae-0.1.1 → xgae-0.1.3}/src/xgae/__init__.py +0 -0
  33. {xgae-0.1.1 → xgae-0.1.3}/src/xgae/engine/responser/xga_non_stream_responser.py +0 -0
  34. {xgae-0.1.1 → xgae-0.1.3}/src/xgae/engine/responser/xga_responser_utils.py +0 -0
  35. {xgae-0.1.1 → xgae-0.1.3}/src/xgae/engine/responser/xga_stream_reponser.py +0 -0
  36. {xgae-0.1.1 → xgae-0.1.3}/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>
@@ -25,23 +25,27 @@
25
25
  <option name="hideEmptyMiddlePackages" value="true" />
26
26
  <option name="showLibraryContents" value="true" />
27
27
  </component>
28
- <component name="PropertiesComponent">{
29
- &quot;keyToString&quot;: {
30
- &quot;ModuleVcsDetector.initialDetectionPerformed&quot;: &quot;true&quot;,
31
- &quot;Python.llm_client.executor&quot;: &quot;Run&quot;,
32
- &quot;Python.utils.executor&quot;: &quot;Run&quot;,
33
- &quot;Python.xga_mcp_tool_box.executor&quot;: &quot;Run&quot;,
34
- &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
35
- &quot;last_opened_file_path&quot;: &quot;/Users/goosezzy/DevelopSpace/xgae&quot;,
36
- &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
37
- &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
38
- &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
39
- &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
40
- &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
41
- &quot;settings.editor.selected.configurable&quot;: &quot;preferences.general&quot;,
42
- &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
28
+ <component name="PropertiesComponent"><![CDATA[{
29
+ "keyToString": {
30
+ "ModuleVcsDetector.initialDetectionPerformed": "true",
31
+ "Python.llm_client.executor": "Run",
32
+ "Python.run_xga_engine.executor": "Run",
33
+ "Python.setup_env.executor": "Run",
34
+ "Python.utils.executor": "Run",
35
+ "Python.xga_engine.executor": "Run",
36
+ "Python.xga_mcp_tool_box.executor": "Debug",
37
+ "Python.xga_prompt_builder.executor": "Debug",
38
+ "RunOnceActivity.ShowReadmeOnStart": "true",
39
+ "last_opened_file_path": "/Users/sharkystar/DevProjects/xga/xgae",
40
+ "node.js.detected.package.eslint": "true",
41
+ "node.js.detected.package.tslint": "true",
42
+ "node.js.selected.package.eslint": "(autodetect)",
43
+ "node.js.selected.package.tslint": "(autodetect)",
44
+ "nodejs_package_manager_path": "npm",
45
+ "settings.editor.selected.configurable": "com.intellij.pycharm.community.ide.impl.configuration.PythonContentEntriesConfigurable",
46
+ "vue.rearranger.settings.migration": "true"
43
47
  }
44
- }</component>
48
+ }]]></component>
45
49
  <component name="RecentsManager">
46
50
  <key name="MoveFile.RECENT_KEYS">
47
51
  <recent name="$PROJECT_DIR$/src/xgae/engine/responser" />
@@ -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="6282000" />
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="1755657339432" 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.3
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.3"
4
4
  description = "Extreme General Agent Engine"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"
@@ -2,7 +2,9 @@ from typing import Union, Optional, Dict, List, Any, Literal
2
2
  from dataclasses import dataclass
3
3
  from abc import ABC, abstractmethod
4
4
 
5
-
5
+ class XGAError(Exception):
6
+ """Custom exception for errors in the XGA system."""
7
+ pass
6
8
 
7
9
  @dataclass
8
10
  class XGAMessage:
@@ -20,7 +22,8 @@ class XGAToolSchema:
20
22
  tool_name: str
21
23
  server_name: str
22
24
  description: str
23
- input_schema: Optional[str]
25
+ input_schema: Dict[str, Any]
26
+ metadata: Optional[Dict[str, Any]]
24
27
 
25
28
 
26
29
  @dataclass
@@ -0,0 +1,99 @@
1
+
2
+ from typing import List, Any, Dict, Optional, AsyncGenerator
3
+ from uuid import uuid4
4
+
5
+ from xgae.engine.xga_base import XGAMessage, 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 XGATaskEngine():
13
+ def __init__(self,
14
+ session_id: Optional[str] = None,
15
+ task_id: Optional[str] = None,
16
+ agent_id: Optional[str] = None,
17
+ trace_id: Optional[str] = None,
18
+ system_prompt: Optional[str] = None,
19
+ llm_config: Optional[Dict[str, Any]] = None,
20
+ prompt_builder: Optional[XGAPromptBuilder] = None,
21
+ tool_box: Optional[XGAToolBox] = None):
22
+ self.session_id = session_id if session_id else f"xga_sid_{uuid4()}"
23
+ self.task_id = task_id if task_id else f"xga_task_{uuid4()}"
24
+ self.agent_id = agent_id
25
+ self.trace_id = trace_id if trace_id else langfuse.create_trace_id()
26
+
27
+ self.messages: List[XGAMessage] = []
28
+ self.llm_client = LLMClient(llm_config)
29
+ self.model_name = self.llm_client.model_name
30
+ self.is_stream = self.llm_client.is_stream
31
+
32
+ self.prompt_builder = prompt_builder or XGAPromptBuilder(system_prompt)
33
+ self.tool_box = tool_box or XGAMcpToolBox()
34
+
35
+
36
+ async def __async_init__(self, general_tools:List[str], custom_tools: List[str]) -> None:
37
+ await self.tool_box.load_mcp_tools_schema()
38
+ await self.tool_box.creat_task_tool_box(self.task_id, general_tools, custom_tools)
39
+ general_tool_schemas = self.tool_box.get_task_tool_schemas(self.task_id, "general_tool")
40
+ custom_tool_schemas = self.tool_box.get_task_tool_schemas(self.task_id, "custom_tool")
41
+
42
+ self.task_prompt = self.prompt_builder.build_task_prompt(self.model_name, general_tool_schemas, custom_tool_schemas)
43
+
44
+ @classmethod
45
+ async def create(cls,
46
+ session_id: Optional[str] = None,
47
+ task_id: Optional[str] = None,
48
+ agent_id: Optional[str] = None,
49
+ trace_id: Optional[str] = None,
50
+ system_prompt: Optional[str] = None,
51
+ general_tools: Optional[List[str]] = None,
52
+ custom_tools: Optional[List[str]] = None,
53
+ llm_config: Optional[Dict[str, Any]] = None,
54
+ prompt_builder: Optional[XGAPromptBuilder] = None,
55
+ tool_box: Optional[XGAToolBox] = None) -> 'XGATaskEngine':
56
+ engine: XGATaskEngine = cls(session_id=session_id,
57
+ task_id=task_id,
58
+ agent_id=agent_id,
59
+ trace_id=trace_id,
60
+ system_prompt=system_prompt,
61
+ llm_config=llm_config,
62
+ prompt_builder=prompt_builder,
63
+ tool_box=tool_box)
64
+ general_tools = general_tools or ["*"]
65
+ custom_tools = custom_tools or []
66
+ await engine.__async_init__(general_tools, custom_tools)
67
+ return engine
68
+
69
+
70
+ async def run_task(self, task_messages: List[Dict[str, Any]]) -> AsyncGenerator:
71
+ try:
72
+ yield self.task_prompt
73
+
74
+ finally:
75
+ await self.tool_box.destroy_task_tool_box(self.task_id)
76
+
77
+
78
+ def _run_task_once(self):
79
+ pass
80
+
81
+
82
+ def add_message(self, message: XGAMessage):
83
+ message.message_id = f"xga_msg_{uuid4()}"
84
+ message.session_id = self.session_id
85
+ message.agent_id = self.agent_id
86
+ self.messages.append(message)
87
+
88
+ if __name__ == "__main__":
89
+ import asyncio
90
+
91
+ async def main():
92
+ tool_box = XGAMcpToolBox(custom_mcp_server_file="mcpservers/custom_servers.json")
93
+ engine = await XGATaskEngine.create(tool_box=tool_box, custom_tools=["bomc_fault.*"])
94
+ # engine = await XGATaskEngine.create()
95
+
96
+ async for chunk in engine.run_task(task_messages=[{}]):
97
+ print(chunk)
98
+
99
+ asyncio.run(main())
@@ -1,21 +1,22 @@
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
7
8
  from langchain_mcp_adapters.tools import load_mcp_tools
8
9
 
9
- from xgae.engine.xga_base import XGAToolSchema, XGAToolBox, XGAToolResult
10
- from xgae.utils.setup_env import XGAError
11
-
10
+ from xgae.engine.xga_base import XGAError, XGAToolSchema, XGAToolBox, XGAToolResult
11
+ from xgae.utils.setup_env import langfuse
12
12
 
13
13
  class XGAMcpToolBox(XGAToolBox):
14
14
  GENERAL_MCP_SERVER_NAME = "xga_general"
15
15
 
16
16
  def __init__(self,
17
- custom_mcp_server_config: Optional[Dict[str, Any]] = None,
18
- custom_mcp_server_file: Optional[str] = None):
17
+ custom_mcp_server_file: Optional[str] = None,
18
+ custom_mcp_server_config: Optional[Dict[str, Any]] = None
19
+ ):
19
20
  general_mcp_server_config = self._load_mcp_servers_config("mcpservers/xga_server.json")
20
21
  tool_box_mcp_server_config = general_mcp_server_config.get("mcpServers", {})
21
22
 
@@ -31,6 +32,8 @@ class XGAMcpToolBox(XGAToolBox):
31
32
  self.mcp_tool_schemas: Dict[str, List[XGAToolSchema]] = {}
32
33
  self.task_tool_schemas: Dict[str, Dict[str,XGAToolSchema]] = {}
33
34
 
35
+ self.is_loaded_tool_schemas = False
36
+
34
37
  @override
35
38
  async def creat_task_tool_box(self, task_id: str, general_tools: List[str], custom_tools: List[str]):
36
39
  task_tool_schemas = {}
@@ -41,7 +44,7 @@ class XGAMcpToolBox(XGAToolBox):
41
44
  for tool_schema in general_tool_schemas:
42
45
  if tool_schema.tool_name in general_tools:
43
46
  task_tool_schemas[tool_schema.tool_name] = tool_schema
44
- task_tool_schemas.pop("end_task")
47
+ task_tool_schemas.pop("end_task", None)
45
48
 
46
49
  for server_tool_name in custom_tools:
47
50
  parts = server_tool_name.split(".")
@@ -122,20 +125,35 @@ class XGAMcpToolBox(XGAToolBox):
122
125
 
123
126
  return result
124
127
 
128
+
125
129
  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)
130
+ if not self.is_loaded_tool_schemas:
131
+ for server_name in self.mcp_server_names:
132
+ self.mcp_tool_schemas[server_name] = []
133
+ mcp_tools = await self._mcp_client.get_tools(server_name=server_name)
134
+
135
+ for tool in mcp_tools:
136
+ input_schema = tool.args_schema
137
+ if server_name == self.GENERAL_MCP_SERVER_NAME:
138
+ input_schema['properties'].pop("task_id", None)
139
+ if 'task_id' in input_schema['required']:
140
+ input_schema['required'].remove('task_id')
141
+ params_properties = input_schema.get("properties", {})
142
+ for param_properties in params_properties.values():
143
+ param_properties.pop("title", None)
144
+
145
+ metadata = tool.metadata or {}
146
+ tool_schema = XGAToolSchema(tool_name=tool.name,
147
+ server_name=server_name,
148
+ description=tool.description,
149
+ input_schema=input_schema,
150
+ metadata=metadata)
151
+ self.mcp_tool_schemas[server_name].append(tool_schema)
152
+ self.is_loaded_tool_schemas = True
153
+
154
+ async def reload_mcp_tools_schema(self) -> None:
155
+ self.is_loaded_tool_schemas = False
156
+ await self.load_mcp_tools_schema()
139
157
 
140
158
  @staticmethod
141
159
  def _load_mcp_servers_config(mcp_config_path: str) -> Dict[str, Any]:
@@ -164,10 +182,11 @@ class XGAMcpToolBox(XGAToolBox):
164
182
  if __name__ == "__main__":
165
183
  import asyncio
166
184
  from dataclasses import asdict
185
+
167
186
  async def main():
168
187
  task_id = "task1"
169
- mcp_tool_box = XGAMcpToolBox(custom_mcp_server_file="mcpservers/custom_servers.json")
170
- #mcp_tool_box = XGAMcpToolBox()
188
+ #mcp_tool_box = XGAMcpToolBox(custom_mcp_server_file="mcpservers/custom_servers.json")
189
+ mcp_tool_box = XGAMcpToolBox()
171
190
  await mcp_tool_box.load_mcp_tools_schema()
172
191
  await mcp_tool_box.creat_task_tool_box(task_id=task_id, general_tools=["*"], custom_tools=["bomc_fault.*"])
173
192
  tool_schemas = mcp_tool_box.get_task_tool_schemas(task_id, "general_tool")
@@ -189,4 +208,5 @@ if __name__ == "__main__":
189
208
  print(f"call complete result: {result}")
190
209
 
191
210
  await mcp_tool_box.destroy_task_tool_box(task_id)
211
+
192
212
  asyncio.run(main())
@@ -0,0 +1,97 @@
1
+ import json
2
+ import datetime
3
+ from typing import Optional, List
4
+
5
+ from xga_base import XGAToolSchema, XGAError
6
+ from xgae.utils.utils import read_file, format_file_with_args
7
+
8
+
9
+ class XGAPromptBuilder():
10
+ def __init__(self, system_prompt: Optional[str] = None):
11
+ self.system_prompt = system_prompt
12
+
13
+ def build_task_prompt(self, model_name: str, general_tool_schemas: List[XGAToolSchema], custom_tool_schemas: List[XGAToolSchema])-> str:
14
+ if self.system_prompt is None:
15
+ self.system_prompt = self._load_default_system_prompt(model_name)
16
+
17
+ task_prompt = self.system_prompt
18
+
19
+ tool_prompt = self.build_general_tool_prompt(general_tool_schemas)
20
+ task_prompt = task_prompt + "\n" + tool_prompt
21
+
22
+ tool_prompt = self.build_custom_tool_prompt(custom_tool_schemas)
23
+ task_prompt = task_prompt + "\n" + tool_prompt
24
+
25
+ return task_prompt
26
+
27
+ def build_general_tool_prompt(self, tool_schemas:List[XGAToolSchema])-> str:
28
+ tool_prompt = ""
29
+ tool_schemas = tool_schemas or []
30
+ if len(tool_schemas) > 0:
31
+ tool_prompt = read_file("templates/general_tool_prompt_template.txt")
32
+ example_prompt = ""
33
+ openai_schemas = []
34
+ for tool_schema in tool_schemas:
35
+ openai_schema = {}
36
+ openai_schema["type"] = "function"
37
+ openai_function = {}
38
+ openai_schema["function"] = openai_function
39
+
40
+ openai_function["name"] = tool_schema.tool_name
41
+ openai_function["description"] = tool_schema.description if tool_schema.description else 'No description available'
42
+
43
+ openai_parameters = {}
44
+ input_schema = tool_schema.input_schema
45
+ openai_function["parameters"] = openai_parameters
46
+ openai_parameters["type"] = input_schema["type"]
47
+ openai_parameters["properties"] = input_schema.get("properties", {})
48
+ openai_parameters["required"] = input_schema["required"]
49
+
50
+ openai_schemas.append(openai_schema)
51
+
52
+ metadata = tool_schema.metadata or {}
53
+ example = metadata.get("example", None)
54
+ if example:
55
+ example_prompt += f"\n{example}\n"
56
+
57
+ schema_prompt = json.dumps(openai_schemas, ensure_ascii=False, indent=2)
58
+ tool_prompt = tool_prompt.format(tool_schemas=schema_prompt, tool_examples=example_prompt)
59
+ return tool_prompt
60
+
61
+
62
+ def build_custom_tool_prompt(self, tool_schemas:List[XGAToolSchema])-> str:
63
+ tool_prompt = ""
64
+ tool_schemas = tool_schemas or []
65
+ if len(tool_schemas) > 0:
66
+ tool_prompt = read_file("templates/custom_tool_prompt_template.txt")
67
+ tool_info = ""
68
+ for tool_schema in tool_schemas:
69
+ description = tool_schema.description if tool_schema.description else 'No description available'
70
+ tool_info += f"- **{tool_schema.tool_name}**: {description}\n"
71
+ parameters = tool_schema.input_schema.get("properties", {})
72
+ tool_info += f" Parameters: {parameters}\n"
73
+ tool_prompt = tool_prompt.replace("{tool_schemas}", tool_info)
74
+
75
+ return tool_prompt
76
+
77
+ def _load_default_system_prompt(self, model_name) -> Optional[str]:
78
+ if "gemini-2.5-flash" in model_name.lower() and "gemini-2.5-pro" not in model_name.lower():
79
+ system_prompt_template = read_file("templates/gemini_system_prompt_template.txt")
80
+ else:
81
+ system_prompt_template = read_file("templates/system_prompt_template.txt")
82
+
83
+ system_prompt = format_file_with_args(system_prompt_template, {"datetime": datetime})
84
+
85
+ system_prompt = system_prompt.format(
86
+ current_date=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d'),
87
+ current_time=datetime.datetime.now(datetime.timezone.utc).strftime('%H:%M:%S'),
88
+ current_year=datetime.datetime.now(datetime.timezone.utc).strftime('%Y')
89
+ )
90
+
91
+ if "anthropic" not in model_name.lower():
92
+ sample_response = read_file("templates/system_prompt_response_sample.txt")
93
+ system_prompt = system_prompt + "\n\n <sample_assistant_response>" + sample_response + "</sample_assistant_response>"
94
+
95
+ return system_prompt
96
+
97
+
@@ -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,96 @@
1
+ import logging
2
+ import os
3
+
4
+ from langfuse import Langfuse
5
+
6
+ _log_initialized = False
7
+
8
+ def setup_logging() -> None:
9
+ global _log_initialized
10
+ if not _log_initialized:
11
+ import colorlog
12
+ from dotenv import load_dotenv
13
+ load_dotenv()
14
+
15
+ env_log_level = os.getenv("LOG_LEVEL", "INFO")
16
+ env_log_file = os.getenv("LOG_FILE", "log/xga.log")
17
+ log_level = getattr(logging, env_log_level.upper(), logging.INFO)
18
+
19
+ log_dir = os.path.dirname(env_log_file)
20
+ if log_dir and not os.path.exists(log_dir):
21
+ os.makedirs(log_dir, exist_ok=True)
22
+ else:
23
+ os.remove(env_log_file)
24
+
25
+ logger = logging.getLogger()
26
+ for handler in logger.handlers[:]:
27
+ logger.removeHandler(handler)
28
+
29
+
30
+
31
+ log_colors = {
32
+ 'DEBUG': 'cyan',
33
+ 'INFO': 'green',
34
+ 'WARNING': 'yellow',
35
+ 'ERROR': 'red',
36
+ 'CRITICAL': 'red,bg_white'
37
+ }
38
+
39
+ console_formatter = colorlog.ColoredFormatter('%(log_color)s%(asctime)s - %(levelname)-8s%(reset)s %(white)s%(message)s',
40
+ log_colors=log_colors,
41
+ datefmt='%Y-%m-%d %H:%M:%S'
42
+ )
43
+
44
+ file_formatter = logging.Formatter(
45
+ '%(asctime)s -%(levelname)-8s %(message)s',
46
+ datefmt='%Y-%m-%d %H:%M:%S'
47
+ )
48
+
49
+ console_handler = logging.StreamHandler()
50
+ console_handler.setFormatter(console_formatter)
51
+
52
+ file_handler = logging.FileHandler(env_log_file, encoding='utf-8')
53
+ file_handler.setFormatter(file_formatter)
54
+
55
+ logger.addHandler(console_handler)
56
+ logger.addHandler(file_handler)
57
+
58
+ logger.setLevel(log_level)
59
+
60
+ logging.info(f"Logger is initialized, log_level={env_log_level}, log_file={env_log_file}")
61
+
62
+ _log_initialized = True
63
+
64
+ setup_logging()
65
+
66
+ _langfuse_initialized = False
67
+
68
+ def setup_langfuse() -> Langfuse:
69
+ global _langfuse_initialized
70
+ _langfuse = None
71
+ if not _langfuse_initialized:
72
+ env_public_key = os.getenv("LANGFUSE_PUBLIC_KEY")
73
+ env_secret_key = os.getenv("LANGFUSE_SECRET_KEY")
74
+ env_host = os.getenv("LANGFUSE_HOST", "https://cloud.langfuse.com")
75
+ if env_public_key and env_secret_key:
76
+ _langfuse = Langfuse(tracing_enabled=True,
77
+ public_key=env_public_key,
78
+ secret_key=env_secret_key,
79
+ host=env_host)
80
+ logging.info("Langfuse initialized Successfully by Key !")
81
+ else:
82
+ _langfuse = Langfuse(tracing_enabled=False)
83
+ logging.warning("Not set key, Langfuse is disabled!")
84
+
85
+ _langfuse_initialized = True
86
+ return _langfuse
87
+
88
+ langfuse: Langfuse = Langfuse if _langfuse_initialized else setup_langfuse()
89
+
90
+
91
+ if __name__ == "__main__":
92
+ try:
93
+ trace_id = langfuse.create_trace_id()
94
+ print(f"trace_id={trace_id}")
95
+ except Exception as e:
96
+ handle_error(e)