xgae 0.1.1__py3-none-any.whl → 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of xgae might be problematic. Click here for more details.
- xgae/engine/xga_base.py +2 -1
- xgae/engine/xga_engine.py +48 -12
- xgae/engine/xga_mcp_tool_box.py +39 -18
- xgae/engine/xga_prompt_builder.py +97 -20
- xgae/utils/llm_client.py +2 -5
- xgae/utils/setup_env.py +76 -61
- {xgae-0.1.1.dist-info → xgae-0.1.2.dist-info}/METADATA +1 -1
- xgae-0.1.2.dist-info/RECORD +13 -0
- xgae-0.1.1.dist-info/RECORD +0 -13
- {xgae-0.1.1.dist-info → xgae-0.1.2.dist-info}/WHEEL +0 -0
xgae/engine/xga_base.py
CHANGED
xgae/engine/xga_engine.py
CHANGED
|
@@ -8,6 +8,7 @@ from xgae.utils.setup_env import langfuse
|
|
|
8
8
|
from xga_prompt_builder import XGAPromptBuilder
|
|
9
9
|
from xga_mcp_tool_box import XGAMcpToolBox
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
class XGAEngine():
|
|
12
13
|
def __init__(self,
|
|
13
14
|
session_id: Optional[str] = None,
|
|
@@ -30,18 +31,39 @@ class XGAEngine():
|
|
|
30
31
|
self.task_id = None
|
|
31
32
|
self.trace_id = trace_id if trace_id else langfuse.create_trace_id()
|
|
32
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
|
+
|
|
33
55
|
|
|
34
56
|
async def run_task(self,
|
|
35
57
|
task_messages: List[Dict[str, Any]],
|
|
36
|
-
task_id: Optional[str],
|
|
37
|
-
|
|
58
|
+
task_id: Optional[str] = None,
|
|
59
|
+
system_prompt: Optional[str] = None,
|
|
38
60
|
general_tools: Optional[List[str]] = ["*"],
|
|
39
61
|
custom_tools: Optional[List[str]] = []) -> AsyncGenerator:
|
|
40
62
|
try:
|
|
41
63
|
self.task_id = task_id if task_id else f"xga_task_{uuid4()}"
|
|
42
64
|
await self.tool_box.creat_task_tool_box(self.task_id, general_tools, custom_tools)
|
|
43
|
-
|
|
44
|
-
yield
|
|
65
|
+
task_prompt = self.build_task_prompt(system_prompt)
|
|
66
|
+
yield task_prompt
|
|
45
67
|
|
|
46
68
|
finally:
|
|
47
69
|
await self.tool_box.destroy_task_tool_box(self.task_id)
|
|
@@ -50,20 +72,34 @@ class XGAEngine():
|
|
|
50
72
|
def _run_task_once(self):
|
|
51
73
|
pass
|
|
52
74
|
|
|
53
|
-
|
|
54
|
-
self.
|
|
55
|
-
system_prompt = self.prompt_builder.build_system_prompt(self.model_name, prompt_template)
|
|
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)
|
|
56
77
|
|
|
57
|
-
tool_schemas =
|
|
58
|
-
|
|
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
|
|
59
81
|
|
|
60
|
-
tool_schemas =
|
|
61
|
-
|
|
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
|
|
62
85
|
|
|
63
|
-
return
|
|
86
|
+
return task_prompt
|
|
64
87
|
|
|
65
88
|
def add_message(self, message: XGAMessage):
|
|
66
89
|
message.message_id = f"xga_msg_{uuid4()}"
|
|
67
90
|
message.session_id = self.session_id
|
|
68
91
|
message.agent_id = self.agent_id
|
|
69
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())
|
xgae/engine/xga_mcp_tool_box.py
CHANGED
|
@@ -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())
|
|
@@ -1,38 +1,115 @@
|
|
|
1
1
|
import datetime
|
|
2
|
+
import sys
|
|
3
|
+
import json
|
|
2
4
|
|
|
3
5
|
from typing import Optional, List
|
|
6
|
+
from io import StringIO
|
|
4
7
|
|
|
5
8
|
from xga_base import XGAToolSchema
|
|
6
9
|
from xgae.utils.setup_env import read_file, XGAError
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
class XGAPromptBuilder():
|
|
10
|
-
def __init__(self,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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")
|
|
18
76
|
else:
|
|
19
|
-
|
|
20
|
-
self.system_prompt_template = _system_prompt_template.format(
|
|
21
|
-
current_date=datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d'),
|
|
22
|
-
current_time=datetime.datetime.now(datetime.timezone.utc).strftime('%H:%M:%S'),
|
|
23
|
-
current_year=datetime.datetime.now(datetime.timezone.utc).strftime('%Y')
|
|
24
|
-
)
|
|
77
|
+
org_prompt_template = read_file("templates/system_prompt_template.txt")
|
|
25
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
|
|
26
92
|
|
|
27
|
-
|
|
28
|
-
|
|
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>"
|
|
29
102
|
|
|
30
103
|
return system_prompt
|
|
31
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)
|
|
32
112
|
|
|
33
|
-
|
|
34
|
-
pass
|
|
113
|
+
print(prompt)
|
|
35
114
|
|
|
36
115
|
|
|
37
|
-
def build_custom_tool_prompt(self, model_name:str, prompt_template: str, tool_schemas:List[XGAToolSchema])-> str:
|
|
38
|
-
pass
|
xgae/utils/llm_client.py
CHANGED
|
@@ -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
|
xgae/utils/setup_env.py
CHANGED
|
@@ -5,81 +5,102 @@ import traceback
|
|
|
5
5
|
from langfuse import Langfuse
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
"""Custom exception for errors in the XGA system."""
|
|
10
|
-
pass
|
|
11
|
-
|
|
12
|
-
langfuse: Langfuse = None
|
|
13
|
-
|
|
14
|
-
def setup_langfuse() -> None:
|
|
15
|
-
env_public_key = os.getenv("LANGFUSE_PUBLIC_KEY")
|
|
16
|
-
env_secret_key = os.getenv("LANGFUSE_SECRET_KEY")
|
|
17
|
-
env_host = os.getenv("LANGFUSE_HOST", "https://cloud.langfuse.com")
|
|
18
|
-
global langfuse
|
|
19
|
-
if env_public_key and env_secret_key:
|
|
20
|
-
langfuse = Langfuse(tracing_enabled=True,
|
|
21
|
-
public_key=env_public_key,
|
|
22
|
-
secret_key=env_secret_key,
|
|
23
|
-
host=env_host)
|
|
24
|
-
logging.info("utils.setup_langfuse: Langfuse initialized!")
|
|
25
|
-
else:
|
|
26
|
-
langfuse = Langfuse(tracing_enabled=False)
|
|
27
|
-
logging.warning("utils.setup_langfuse: Langfuse is disabled!")
|
|
8
|
+
_log_initialized = False
|
|
28
9
|
|
|
29
10
|
def setup_logging() -> None:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
+
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
log_colors = {
|
|
34
|
+
'DEBUG': 'cyan',
|
|
35
|
+
'INFO': 'green',
|
|
36
|
+
'WARNING': 'yellow',
|
|
37
|
+
'ERROR': 'red',
|
|
38
|
+
'CRITICAL': 'red,bg_white'
|
|
39
|
+
}
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
+
)
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
file_formatter = logging.Formatter(
|
|
47
|
+
'%(asctime)s -%(levelname)-8s %(message)s',
|
|
48
|
+
datefmt='%Y-%m-%d %H:%M:%S'
|
|
49
|
+
)
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
'INFO': 'green',
|
|
49
|
-
'WARNING': 'yellow',
|
|
50
|
-
'ERROR': 'red',
|
|
51
|
-
'CRITICAL': 'red,bg_white'
|
|
52
|
-
}
|
|
51
|
+
console_handler = logging.StreamHandler()
|
|
52
|
+
console_handler.setFormatter(console_formatter)
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
datefmt='%Y-%m-%d %H:%M:%S'
|
|
57
|
-
)
|
|
54
|
+
file_handler = logging.FileHandler(env_log_file, encoding='utf-8')
|
|
55
|
+
file_handler.setFormatter(file_formatter)
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
datefmt='%Y-%m-%d %H:%M:%S'
|
|
62
|
-
)
|
|
57
|
+
logger.addHandler(console_handler)
|
|
58
|
+
logger.addHandler(file_handler)
|
|
63
59
|
|
|
64
|
-
|
|
65
|
-
console_handler.setFormatter(console_formatter)
|
|
60
|
+
logger.setLevel(log_level)
|
|
66
61
|
|
|
67
|
-
|
|
68
|
-
file_handler.setFormatter(file_formatter)
|
|
62
|
+
logging.info(f"Logger is initialized, log_level={env_log_level}, log_file={env_log_file}")
|
|
69
63
|
|
|
70
|
-
|
|
71
|
-
logger.addHandler(file_handler)
|
|
64
|
+
_log_initialized = True
|
|
72
65
|
|
|
73
|
-
|
|
66
|
+
setup_logging()
|
|
74
67
|
|
|
75
|
-
logging.info(f"Logger is initialized, log_level={env_log_level}, log_file={env_log_file}")
|
|
76
68
|
|
|
69
|
+
class XGAError(Exception):
|
|
70
|
+
"""Custom exception for errors in the XGA system."""
|
|
71
|
+
pass
|
|
77
72
|
|
|
78
73
|
def handle_error(e: Exception) -> None:
|
|
79
74
|
logging.error("An error occurred: %s", str(e))
|
|
80
75
|
logging.error("Traceback details:\n%s", traceback.format_exc())
|
|
81
76
|
raise (e) from e
|
|
82
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
|
+
|
|
83
104
|
def read_file(file_path: str) -> str:
|
|
84
105
|
if not os.path.exists(file_path):
|
|
85
106
|
logging.error(f"File '{file_path}' not found")
|
|
@@ -93,15 +114,9 @@ def read_file(file_path: str) -> str:
|
|
|
93
114
|
logging.error(f"Read file '{file_path}' failed")
|
|
94
115
|
handle_error(e)
|
|
95
116
|
|
|
96
|
-
def setup_xga_env() -> None:
|
|
97
|
-
from dotenv import load_dotenv
|
|
98
|
-
load_dotenv()
|
|
99
|
-
setup_logging()
|
|
100
|
-
setup_langfuse()
|
|
101
117
|
|
|
102
118
|
if __name__ == "__main__":
|
|
103
119
|
try:
|
|
104
|
-
setup_xga_env()
|
|
105
120
|
trace_id = langfuse.create_trace_id()
|
|
106
121
|
print(f"trace_id={trace_id}")
|
|
107
122
|
except Exception as e:
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
xgae/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
xgae/engine/xga_base.py,sha256=vOiYWoBze7VrmndYnaNhMzoB1zCT80WtIlOWdp2IrUc,1253
|
|
3
|
+
xgae/engine/xga_engine.py,sha256=AgklNAimyErvn74xUu6aardZvgjqbIR99gCojEmZfO0,4267
|
|
4
|
+
xgae/engine/xga_mcp_tool_box.py,sha256=jRYvZ8eY72KRU0leD-o15fe_E8wjWJtxQZbsIqGVjPU,9753
|
|
5
|
+
xgae/engine/xga_prompt_builder.py,sha256=Q3nrmYAofRkFQFdfSWkP00FZKjWMUQs2cvMs7bvyQgQ,4819
|
|
6
|
+
xgae/engine/responser/xga_non_stream_responser.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
xgae/engine/responser/xga_responser_utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
xgae/engine/responser/xga_stream_reponser.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
xgae/utils/llm_client.py,sha256=UMMK84psLsx36-Nn6Q8X1hl9wd-OdaS9ZhxbRjwNCr0,12149
|
|
10
|
+
xgae/utils/setup_env.py,sha256=qZmVfqaYHtjq5t-zwRt_G3i-QqGPxSb4D2FnFHbhdcY,3689
|
|
11
|
+
xgae-0.1.2.dist-info/METADATA,sha256=iBwWKlpbp7z0ZQgydnieP_2NBf0Z7H0D6AtavbIN3Zc,309
|
|
12
|
+
xgae-0.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
13
|
+
xgae-0.1.2.dist-info/RECORD,,
|
xgae-0.1.1.dist-info/RECORD
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
xgae/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
xgae/engine/xga_base.py,sha256=ZuOVD5mLnfi8rTnDspY8qfEgwefVTTYgf6eY3B_001s,1213
|
|
3
|
-
xgae/engine/xga_engine.py,sha256=3U0F3_ISu5K1CGYhn0RZsIaZkm4OQIrMTIf3N22M7bE,3013
|
|
4
|
-
xgae/engine/xga_mcp_tool_box.py,sha256=3L48c-Wl8QghbudUsZdYemOzEHoOGF0QC-sAh0H1PVI,9047
|
|
5
|
-
xgae/engine/xga_prompt_builder.py,sha256=wPCB6g0QNpKDuvWs5Ix_Z8-OoCFjxqApodb-g-qZrbM,1503
|
|
6
|
-
xgae/engine/responser/xga_non_stream_responser.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
-
xgae/engine/responser/xga_responser_utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
xgae/engine/responser/xga_stream_reponser.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
xgae/utils/llm_client.py,sha256=bsdWLTXRDDpiuEn72a5BuT4FYomE1LjY-thQHbTQ_Fg,12167
|
|
10
|
-
xgae/utils/setup_env.py,sha256=nJHllWuM9kLs_mJg_-j3Lhj8FHtyFjK4CIoDY_SHOxk,3253
|
|
11
|
-
xgae-0.1.1.dist-info/METADATA,sha256=_j2ZiXzJZa-sw_fk7P0sHkKiyYus_ncxoL9YoZEv4iQ,309
|
|
12
|
-
xgae-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
13
|
-
xgae-0.1.1.dist-info/RECORD,,
|
|
File without changes
|